All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver
@ 2017-10-27 19:45 Peter Meerwald-Stadler
  2017-10-27 19:45 ` [PATCH v2 01/13] iio: health: max30102: Temperature should be in milli Celsius Peter Meerwald-Stadler
                   ` (13 more replies)
  0 siblings, 14 replies; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

This patch series reworks the max30102 driver to add support for the MAX30105
part (which add a third LED)

v2:
* send correct patches, sorry for the mess
* fix Matt Ranostay's email address


patches 1 to 3 are bugfix

patches 4 to 6 add minor features and cleanup

patch 8 allows to read the temperature without currently measuring other channels

patches 9 to 11 prepare for adding another LED, more flexibility

patch 12 adds support for the MAX30105 part

patch 13 updates devicetree documentation for the MAX30105 part

Peter Meerwald-Stadler (13):
  iio: health: max30102: Temperature should be in milli Celsius
  iio: health: max30102: Fix missing newline in dev_err
  iio: health: max30102: Remove inconsistent full stop in error message
  iio: health: max30102: Fix mode config values
  iio: health: max30102: Check retval of powermode function
  iio: health: max30102: Add check for part ID
  iio: health: max30102: Introduce intensity channel macro
  iio: health: max30102: Add power enable parameter to get_temp function
  iio: health: max30102: Introduce indices for LED channels
  iio: health: max30102: Move mode setting to buffer_postenable
  iio: health: max30102: Prepare for copying varying number of
    measurements
  iio: health: max30102: Add MAX30105 support
  dt-bindings: iio: health: Add MAX30105 support to max30102.txt

 .../devicetree/bindings/iio/health/max30102.txt    |   8 +-
 drivers/iio/health/max30102.c                      | 310 ++++++++++++++++-----
 2 files changed, 241 insertions(+), 77 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH v2 01/13] iio: health: max30102: Temperature should be in milli Celsius
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 21:09   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 02/13] iio: health: max30102: Fix missing newline in dev_err Peter Meerwald-Stadler
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

As per ABI temperature should be in milli Celsius after scaling,
not Celsius

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 203ffb9..147a8c1 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -371,7 +371,7 @@ static int max30102_read_raw(struct iio_dev *indio_dev,
 		mutex_unlock(&indio_dev->mlock);
 		break;
 	case IIO_CHAN_INFO_SCALE:
-		*val = 1;  /* 0.0625 */
+		*val = 1000;  /* 62.5 */
 		*val2 = 16;
 		ret = IIO_VAL_FRACTIONAL;
 		break;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 02/13] iio: health: max30102: Fix missing newline in dev_err
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
  2017-10-27 19:45 ` [PATCH v2 01/13] iio: health: max30102: Temperature should be in milli Celsius Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:28   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 03/13] iio: health: max30102: Remove inconsistent full stop in error message Peter Meerwald-Stadler
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 147a8c1..62b1b35 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -261,7 +261,7 @@ static int max30102_led_init(struct max30102_data *data)
 
 	ret = max30102_get_current_idx(val, &reg);
 	if (ret) {
-		dev_err(dev, "invalid IR LED current setting %d", val);
+		dev_err(dev, "invalid IR LED current setting %d\n", val);
 		return ret;
 	}
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 03/13] iio: health: max30102: Remove inconsistent full stop in error message
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
  2017-10-27 19:45 ` [PATCH v2 01/13] iio: health: max30102: Temperature should be in milli Celsius Peter Meerwald-Stadler
  2017-10-27 19:45 ` [PATCH v2 02/13] iio: health: max30102: Fix missing newline in dev_err Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:28   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 04/13] iio: health: max30102: Fix mode config values Peter Meerwald-Stadler
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 62b1b35..6ca6182 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -420,7 +420,7 @@ static int max30102_probe(struct i2c_client *client,
 
 	data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config);
 	if (IS_ERR(data->regmap)) {
-		dev_err(&client->dev, "regmap initialization failed.\n");
+		dev_err(&client->dev, "regmap initialization failed\n");
 		return PTR_ERR(data->regmap);
 	}
 	max30102_set_powermode(data, false);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 04/13] iio: health: max30102: Fix mode config values
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (2 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 03/13] iio: health: max30102: Remove inconsistent full stop in error message Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:46   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 05/13] iio: health: max30102: Check retval of powermode function Peter Meerwald-Stadler
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

Table 4 of the datasheet specifies the mode control, these are not
individual bits; add multi LED mode

Add multi-LED mode and fix MODE_MASK (3 bits wide, not 2)

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 6ca6182..13d5312 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -60,9 +60,10 @@
 #define MAX30102_REG_FIFO_CONFIG_AFULL		BIT(0)
 
 #define MAX30102_REG_MODE_CONFIG		0x09
-#define MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN	BIT(0)
-#define MAX30102_REG_MODE_CONFIG_MODE_HR_EN	BIT(1)
-#define MAX30102_REG_MODE_CONFIG_MODE_MASK	0x03
+#define MAX30102_REG_MODE_CONFIG_MODE_HR	0x02 /* red LED */
+#define MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2	0x03 /* red + IR LED */
+#define MAX30102_REG_MODE_CONFIG_MODE_MULTI	0x07 /* multi-LED mode */
+#define MAX30102_REG_MODE_CONFIG_MODE_MASK	GENMASK(2, 0)
 #define MAX30102_REG_MODE_CONFIG_PWR		BIT(7)
 
 #define MAX30102_REG_SPO2_CONFIG		0x0a
@@ -287,11 +288,10 @@ static int max30102_chip_init(struct max30102_data *data)
 	if (ret)
 		return ret;
 
-	/* enable SPO2 mode */
+	/* enable HR + SPO2 mode */
 	ret = regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
 				 MAX30102_REG_MODE_CONFIG_MODE_MASK,
-				 MAX30102_REG_MODE_CONFIG_MODE_HR_EN |
-				 MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN);
+				 MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2);
 	if (ret)
 		return ret;
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 05/13] iio: health: max30102: Check retval of powermode function
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (3 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 04/13] iio: health: max30102: Fix mode config values Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:43   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 06/13] iio: health: max30102: Add check for part ID Peter Meerwald-Stadler
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 13d5312..389a483 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -423,7 +423,10 @@ static int max30102_probe(struct i2c_client *client,
 		dev_err(&client->dev, "regmap initialization failed\n");
 		return PTR_ERR(data->regmap);
 	}
-	max30102_set_powermode(data, false);
+
+	ret = max30102_set_powermode(data, false);
+	if (ret)
+		return ret;
 
 	ret = max30102_chip_init(data);
 	if (ret)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 06/13] iio: health: max30102: Add check for part ID
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (4 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 05/13] iio: health: max30102: Check retval of powermode function Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:38   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 07/13] iio: health: max30102: Introduce intensity channel macro Peter Meerwald-Stadler
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 389a483..c43957e 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -32,6 +32,7 @@
 
 #define MAX30102_REGMAP_NAME	"max30102_regmap"
 #define MAX30102_DRV_NAME	"max30102"
+#define MAX30102_PART_NUMBER	0x15
 
 #define MAX30102_REG_INT_STATUS			0x00
 #define MAX30102_REG_INT_STATUS_PWR_RDY		BIT(0)
@@ -83,6 +84,9 @@
 #define MAX30102_REG_TEMP_INTEGER		0x1f
 #define MAX30102_REG_TEMP_FRACTION		0x20
 
+#define MAX30102_REG_REV_ID			0xfe
+#define MAX30102_REG_PART_ID			0xff
+
 struct max30102_data {
 	struct i2c_client *client;
 	struct iio_dev *indio_dev;
@@ -391,6 +395,7 @@ static int max30102_probe(struct i2c_client *client,
 	struct iio_buffer *buffer;
 	struct iio_dev *indio_dev;
 	int ret;
+	unsigned int reg;
 
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 	if (!indio_dev)
@@ -424,6 +429,19 @@ static int max30102_probe(struct i2c_client *client,
 		return PTR_ERR(data->regmap);
 	}
 
+	/* check part ID */
+	ret = regmap_read(data->regmap, MAX30102_REG_PART_ID, &reg);
+	if (ret)
+		return ret;
+	if (reg != MAX30102_PART_NUMBER)
+		return -ENODEV;
+
+	/* show revision ID */
+	ret = regmap_read(data->regmap, MAX30102_REG_REV_ID, &reg);
+	if (ret)
+		return ret;
+	dev_dbg(&client->dev, "max3010x revision %02x\n", reg);
+
 	ret = max30102_set_powermode(data, false);
 	if (ret)
 		return ret;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 07/13] iio: health: max30102: Introduce intensity channel macro
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (5 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 06/13] iio: health: max30102: Add check for part ID Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:37   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 08/13] iio: health: max30102: Add power enable parameter to get_temp function Peter Meerwald-Stadler
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stalder, Matt Ranostay

Signed-off-by: Peter Meerwald-Stalder <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 44 ++++++++++++++++---------------------------
 1 file changed, 16 insertions(+), 28 deletions(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index c43957e..968b54b 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -106,35 +106,23 @@ static const struct regmap_config max30102_regmap_config = {
 
 static const unsigned long max30102_scan_masks[] = {0x3, 0};
 
+#define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
+		.type = IIO_INTENSITY, \
+		.channel2 = _mod, \
+		.modified = 1, \
+		.scan_index = _si, \
+		.scan_type = { \
+			.sign = 'u', \
+			.shift = 8, \
+			.realbits = 18, \
+			.storagebits = 32, \
+			.endianness = IIO_BE, \
+		}, \
+	}
+
 static const struct iio_chan_spec max30102_channels[] = {
-	{
-		.type = IIO_INTENSITY,
-		.channel2 = IIO_MOD_LIGHT_RED,
-		.modified = 1,
-
-		.scan_index = 0,
-		.scan_type = {
-			.sign = 'u',
-			.shift = 8,
-			.realbits = 18,
-			.storagebits = 32,
-			.endianness = IIO_BE,
-		},
-	},
-	{
-		.type = IIO_INTENSITY,
-		.channel2 = IIO_MOD_LIGHT_IR,
-		.modified = 1,
-
-		.scan_index = 1,
-		.scan_type = {
-			.sign = 'u',
-			.shift = 8,
-			.realbits = 18,
-			.storagebits = 32,
-			.endianness = IIO_BE,
-		},
-	},
+	MAX30102_INTENSITY_CHANNEL(0, IIO_MOD_LIGHT_RED),
+	MAX30102_INTENSITY_CHANNEL(1, IIO_MOD_LIGHT_IR),
 	{
 		.type = IIO_TEMP,
 		.info_mask_separate =
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 08/13] iio: health: max30102: Add power enable parameter to get_temp function
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (6 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 07/13] iio: health: max30102: Introduce intensity channel macro Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:41   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 09/13] iio: health: max30102: Introduce indices for LED channels Peter Meerwald-Stadler
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

Chip must not be in shutdown for reading temperature, so briefly leave
shutdown if buffer is not already running

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 36 +++++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 968b54b..520d905 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -321,20 +321,31 @@ static int max30102_read_temp(struct max30102_data *data, int *val)
 	return 0;
 }
 
-static int max30102_get_temp(struct max30102_data *data, int *val)
+static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
 {
 	int ret;
 
+	if (en) {
+		ret = max30102_set_powermode(data, true);
+		if (ret)
+			return ret;
+	}
+
 	/* start acquisition */
 	ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
 				 MAX30102_REG_TEMP_CONFIG_TEMP_EN,
 				 MAX30102_REG_TEMP_CONFIG_TEMP_EN);
 	if (ret)
-		return ret;
+		goto out;
 
 	msleep(35);
+	ret = max30102_read_temp(data, val);
+
+out:
+	if (en)
+		max30102_set_powermode(data, false);
 
-	return max30102_read_temp(data, val);
+	return ret;
 }
 
 static int max30102_read_raw(struct iio_dev *indio_dev,
@@ -347,20 +358,19 @@ static int max30102_read_raw(struct iio_dev *indio_dev,
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
 		/*
-		 * Temperature reading can only be acquired while engine
-		 * is running
+		 * Temperature reading can only be acquired when not in
+		 * shutdown; leave shutdown briefly when buffer not running
 		 */
 		mutex_lock(&indio_dev->mlock);
-
 		if (!iio_buffer_enabled(indio_dev))
-			ret = -EBUSY;
-		else {
-			ret = max30102_get_temp(data, val);
-			if (!ret)
-				ret = IIO_VAL_INT;
-		}
-
+			ret = max30102_get_temp(data, val, true);
+		else
+			ret = max30102_get_temp(data, val, false);
 		mutex_unlock(&indio_dev->mlock);
+		if (ret)
+			return ret;
+
+		ret = IIO_VAL_INT;
 		break;
 	case IIO_CHAN_INFO_SCALE:
 		*val = 1000;  /* 62.5 */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 09/13] iio: health: max30102: Introduce indices for LED channels
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (7 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 08/13] iio: health: max30102: Add power enable parameter to get_temp function Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:42   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 10/13] iio: health: max30102: Move mode setting to buffer_postenable Peter Meerwald-Stadler
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 520d905..37176c2 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -34,6 +34,11 @@
 #define MAX30102_DRV_NAME	"max30102"
 #define MAX30102_PART_NUMBER	0x15
 
+enum max3012_led_idx {
+	MAX30102_LED_RED,
+	MAX30102_LED_IR,
+};
+
 #define MAX30102_REG_INT_STATUS			0x00
 #define MAX30102_REG_INT_STATUS_PWR_RDY		BIT(0)
 #define MAX30102_REG_INT_STATUS_PROX_INT	BIT(4)
@@ -104,7 +109,10 @@ static const struct regmap_config max30102_regmap_config = {
 	.val_bits = 8,
 };
 
-static const unsigned long max30102_scan_masks[] = {0x3, 0};
+static const unsigned long max30102_scan_masks[] = {
+	BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR),
+	0
+};
 
 #define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
 		.type = IIO_INTENSITY, \
@@ -121,8 +129,8 @@ static const unsigned long max30102_scan_masks[] = {0x3, 0};
 	}
 
 static const struct iio_chan_spec max30102_channels[] = {
-	MAX30102_INTENSITY_CHANNEL(0, IIO_MOD_LIGHT_RED),
-	MAX30102_INTENSITY_CHANNEL(1, IIO_MOD_LIGHT_IR),
+	MAX30102_INTENSITY_CHANNEL(MAX30102_LED_RED, IIO_MOD_LIGHT_RED),
+	MAX30102_INTENSITY_CHANNEL(MAX30102_LED_IR, IIO_MOD_LIGHT_IR),
 	{
 		.type = IIO_TEMP,
 		.info_mask_separate =
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 10/13] iio: health: max30102: Move mode setting to buffer_postenable
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (8 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 09/13] iio: health: max30102: Introduce indices for LED channels Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:56   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 11/13] iio: health: max30102: Prepare for copying varying number of measurements Peter Meerwald-Stadler
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

Move the programming of the mode setting from init() to
buffer_postenable()

Split out a separate function to
only update the power/shutdown bit

This changes permits to more easily implement different
modes of measurements in further patches

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 44 +++++++++++++++++++++++++++----------------
 1 file changed, 28 insertions(+), 16 deletions(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 37176c2..1c7fe63 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -66,6 +66,7 @@ enum max3012_led_idx {
 #define MAX30102_REG_FIFO_CONFIG_AFULL		BIT(0)
 
 #define MAX30102_REG_MODE_CONFIG		0x09
+#define MAX30102_REG_MODE_CONFIG_MODE_NONE	0x00
 #define MAX30102_REG_MODE_CONFIG_MODE_HR	0x02 /* red LED */
 #define MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2	0x03 /* red + IR LED */
 #define MAX30102_REG_MODE_CONFIG_MODE_MULTI	0x07 /* multi-LED mode */
@@ -139,25 +140,41 @@ static const struct iio_chan_spec max30102_channels[] = {
 	},
 };
 
-static int max30102_set_powermode(struct max30102_data *data, bool state)
+static int max30102_set_power(struct max30102_data *data, bool en)
 {
 	return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
 				  MAX30102_REG_MODE_CONFIG_PWR,
-				  state ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
+				  en ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
+}
+
+static int max30102_set_powermode(struct max30102_data *data, u8 mode, bool en)
+{
+	u8 reg = mode;
+
+	if (!en)
+		reg |= MAX30102_REG_MODE_CONFIG_PWR;
+
+	return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
+				  MAX30102_REG_MODE_CONFIG_PWR |
+				  MAX30102_REG_MODE_CONFIG_MODE_MASK, reg);
 }
 
 static int max30102_buffer_postenable(struct iio_dev *indio_dev)
 {
 	struct max30102_data *data = iio_priv(indio_dev);
+	u8 reg;
+
+	reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
 
-	return max30102_set_powermode(data, true);
+	return max30102_set_powermode(data, reg, true);
 }
 
 static int max30102_buffer_predisable(struct iio_dev *indio_dev)
 {
 	struct max30102_data *data = iio_priv(indio_dev);
 
-	return max30102_set_powermode(data, false);
+	return max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
+				      false);
 }
 
 static const struct iio_buffer_setup_ops max30102_buffer_setup_ops = {
@@ -278,7 +295,7 @@ static int max30102_chip_init(struct max30102_data *data)
 	if (ret)
 		return ret;
 
-	/* enable 18-bit HR + SPO2 readings at 400Hz */
+	/* configure 18-bit HR + SpO2 readings at 400Hz */
 	ret = regmap_write(data->regmap, MAX30102_REG_SPO2_CONFIG,
 				(MAX30102_REG_SPO2_CONFIG_ADC_4096_STEPS
 				 << MAX30102_REG_SPO2_CONFIG_ADC_MASK_SHIFT) |
@@ -288,13 +305,6 @@ static int max30102_chip_init(struct max30102_data *data)
 	if (ret)
 		return ret;
 
-	/* enable HR + SPO2 mode */
-	ret = regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
-				 MAX30102_REG_MODE_CONFIG_MODE_MASK,
-				 MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2);
-	if (ret)
-		return ret;
-
 	/* average 4 samples + generate FIFO interrupt */
 	ret = regmap_write(data->regmap, MAX30102_REG_FIFO_CONFIG,
 				(MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES
@@ -334,7 +344,7 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
 	int ret;
 
 	if (en) {
-		ret = max30102_set_powermode(data, true);
+		ret = max30102_set_power(data, true);
 		if (ret)
 			return ret;
 	}
@@ -351,7 +361,7 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
 
 out:
 	if (en)
-		max30102_set_powermode(data, false);
+		max30102_set_power(data, false);
 
 	return ret;
 }
@@ -448,7 +458,9 @@ static int max30102_probe(struct i2c_client *client,
 		return ret;
 	dev_dbg(&client->dev, "max3010x revision %02x\n", reg);
 
-	ret = max30102_set_powermode(data, false);
+	/* clear mode setting, chip shutdown */
+	ret = max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
+				     false);
 	if (ret)
 		return ret;
 
@@ -479,7 +491,7 @@ static int max30102_remove(struct i2c_client *client)
 	struct max30102_data *data = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	max30102_set_powermode(data, false);
+	max30102_set_power(data, false);
 
 	return 0;
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 11/13] iio: health: max30102: Prepare for copying varying number of measurements
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (9 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 10/13] iio: health: max30102: Move mode setting to buffer_postenable Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:52   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 12/13] iio: health: max30102: Add MAX30105 support Peter Meerwald-Stadler
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

Current code assumes always 2 measurements (6 bytes) have to be copied,
prepare for more flexibility

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 1c7fe63..86058f0 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -58,7 +58,7 @@ enum max3012_led_idx {
 #define MAX30102_REG_FIFO_OVR_CTR		0x05
 #define MAX30102_REG_FIFO_RD_PTR		0x06
 #define MAX30102_REG_FIFO_DATA			0x07
-#define MAX30102_REG_FIFO_DATA_ENTRY_LEN	6
+#define MAX30102_REG_FIFO_DATA_BYTES		3
 
 #define MAX30102_REG_FIFO_CONFIG		0x08
 #define MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES	BIT(1)
@@ -198,6 +198,11 @@ static inline int max30102_fifo_count(struct max30102_data *data)
 	return 0;
 }
 
+#define MAX30102_COPY_DATA(i) \
+	memcpy(&data->processed_buffer[(i)], \
+	       &buffer[(i) * MAX30102_REG_FIFO_DATA_BYTES], \
+	       MAX30102_REG_FIFO_DATA_BYTES)
+
 static int max30102_read_measurement(struct max30102_data *data)
 {
 	int ret;
@@ -205,13 +210,13 @@ static int max30102_read_measurement(struct max30102_data *data)
 
 	ret = i2c_smbus_read_i2c_block_data(data->client,
 					    MAX30102_REG_FIFO_DATA,
-					    MAX30102_REG_FIFO_DATA_ENTRY_LEN,
+					    2 * MAX30102_REG_FIFO_DATA_BYTES,
 					    buffer);
 
-	memcpy(&data->processed_buffer[0], &buffer[0], 3);
-	memcpy(&data->processed_buffer[1], &buffer[3], 3);
+	MAX30102_COPY_DATA(0);
+	MAX30102_COPY_DATA(1);
 
-	return (ret == MAX30102_REG_FIFO_DATA_ENTRY_LEN) ? 0 : -EINVAL;
+	return (ret == 2 * MAX30102_REG_FIFO_DATA_BYTES) ? 0 : -EINVAL;
 }
 
 static irqreturn_t max30102_interrupt_handler(int irq, void *private)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 12/13] iio: health: max30102: Add MAX30105 support
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (10 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 11/13] iio: health: max30102: Prepare for copying varying number of measurements Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 21:00   ` Matt Ranostay
  2017-10-27 19:45 ` [PATCH v2 13/13] dt-bindings: iio: health: Add MAX30105 support to max30102.txt Peter Meerwald-Stadler
  2017-11-02 14:44 ` [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Jonathan Cameron
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay

The Maxim MAX30105 part adds a third LED (green) and uses a multi-LED
measuring mode producing three measurements

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
---
 drivers/iio/health/max30102.c | 144 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 130 insertions(+), 14 deletions(-)

diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 86058f0..15ccadc 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -3,6 +3,9 @@
  *
  * Copyright (C) 2017 Matt Ranostay <matt@ranostay.consulting>
  *
+ * Support for MAX30105 optical particle sensor
+ * Copyright (C) 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -13,6 +16,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  *
+ * 7-bit I2C chip address: 0x57
  * TODO: proximity power saving feature
  */
 
@@ -34,9 +38,15 @@
 #define MAX30102_DRV_NAME	"max30102"
 #define MAX30102_PART_NUMBER	0x15
 
+enum max30102_chip_id {
+	max30102,
+	max30105,
+};
+
 enum max3012_led_idx {
 	MAX30102_LED_RED,
 	MAX30102_LED_IR,
+	MAX30105_LED_GREEN,
 };
 
 #define MAX30102_REG_INT_STATUS			0x00
@@ -73,6 +83,11 @@ enum max3012_led_idx {
 #define MAX30102_REG_MODE_CONFIG_MODE_MASK	GENMASK(2, 0)
 #define MAX30102_REG_MODE_CONFIG_PWR		BIT(7)
 
+#define MAX30102_REG_MODE_CONTROL_SLOT21	0x11 /* multi-LED control */
+#define MAX30102_REG_MODE_CONTROL_SLOT43	0x12
+#define MAX30102_REG_MODE_CONTROL_SLOT_MASK	(GENMASK(6, 4) | GENMASK(2, 0))
+#define MAX30102_REG_MODE_CONTROL_SLOT_SHIFT	4
+
 #define MAX30102_REG_SPO2_CONFIG		0x0a
 #define MAX30102_REG_SPO2_CONFIG_PULSE_411_US	0x03
 #define MAX30102_REG_SPO2_CONFIG_SR_400HZ	0x03
@@ -83,6 +98,7 @@ enum max3012_led_idx {
 
 #define MAX30102_REG_RED_LED_CONFIG		0x0c
 #define MAX30102_REG_IR_LED_CONFIG		0x0d
+#define MAX30105_REG_GREEN_LED_CONFIG		0x0e
 
 #define MAX30102_REG_TEMP_CONFIG		0x21
 #define MAX30102_REG_TEMP_CONFIG_TEMP_EN	BIT(0)
@@ -98,9 +114,10 @@ struct max30102_data {
 	struct iio_dev *indio_dev;
 	struct mutex lock;
 	struct regmap *regmap;
+	enum max30102_chip_id chip_id;
 
-	u8 buffer[8];
-	__be32 processed_buffer[2]; /* 2 x 18-bit (padded to 32-bits) */
+	u8 buffer[12];
+	__be32 processed_buffer[3]; /* 3 x 18-bit (padded to 32-bits) */
 };
 
 static const struct regmap_config max30102_regmap_config = {
@@ -115,6 +132,13 @@ static const unsigned long max30102_scan_masks[] = {
 	0
 };
 
+static const unsigned long max30105_scan_masks[] = {
+	BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR),
+	BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR) |
+		BIT(MAX30105_LED_GREEN),
+	0
+};
+
 #define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
 		.type = IIO_INTENSITY, \
 		.channel2 = _mod, \
@@ -140,6 +164,18 @@ static const struct iio_chan_spec max30102_channels[] = {
 	},
 };
 
+static const struct iio_chan_spec max30105_channels[] = {
+	MAX30102_INTENSITY_CHANNEL(MAX30102_LED_RED, IIO_MOD_LIGHT_RED),
+	MAX30102_INTENSITY_CHANNEL(MAX30102_LED_IR, IIO_MOD_LIGHT_IR),
+	MAX30102_INTENSITY_CHANNEL(MAX30105_LED_GREEN, IIO_MOD_LIGHT_GREEN),
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = -1,
+	},
+};
+
 static int max30102_set_power(struct max30102_data *data, bool en)
 {
 	return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
@@ -159,12 +195,40 @@ static int max30102_set_powermode(struct max30102_data *data, u8 mode, bool en)
 				  MAX30102_REG_MODE_CONFIG_MODE_MASK, reg);
 }
 
+#define MAX30102_MODE_CONTROL_LED_SLOTS(slot2, slot1) \
+	((slot2 << MAX30102_REG_MODE_CONTROL_SLOT_SHIFT) | slot1)
+
 static int max30102_buffer_postenable(struct iio_dev *indio_dev)
 {
 	struct max30102_data *data = iio_priv(indio_dev);
+	int ret;
 	u8 reg;
 
-	reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
+	switch (*indio_dev->active_scan_mask) {
+	case BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR):
+		reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
+		break;
+	case BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR) |
+	     BIT(MAX30105_LED_GREEN):
+		ret = regmap_update_bits(data->regmap,
+					 MAX30102_REG_MODE_CONTROL_SLOT21,
+					 MAX30102_REG_MODE_CONTROL_SLOT_MASK,
+					 MAX30102_MODE_CONTROL_LED_SLOTS(2, 1));
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(data->regmap,
+					 MAX30102_REG_MODE_CONTROL_SLOT43,
+					 MAX30102_REG_MODE_CONTROL_SLOT_MASK,
+					 MAX30102_MODE_CONTROL_LED_SLOTS(0, 3));
+		if (ret)
+			return ret;
+
+		reg = MAX30102_REG_MODE_CONFIG_MODE_MULTI;
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	return max30102_set_powermode(data, reg, true);
 }
@@ -203,32 +267,46 @@ static inline int max30102_fifo_count(struct max30102_data *data)
 	       &buffer[(i) * MAX30102_REG_FIFO_DATA_BYTES], \
 	       MAX30102_REG_FIFO_DATA_BYTES)
 
-static int max30102_read_measurement(struct max30102_data *data)
+static int max30102_read_measurement(struct max30102_data *data,
+				     unsigned int measurements)
 {
 	int ret;
 	u8 *buffer = (u8 *) &data->buffer;
 
 	ret = i2c_smbus_read_i2c_block_data(data->client,
 					    MAX30102_REG_FIFO_DATA,
-					    2 * MAX30102_REG_FIFO_DATA_BYTES,
+					    measurements *
+					    MAX30102_REG_FIFO_DATA_BYTES,
 					    buffer);
 
-	MAX30102_COPY_DATA(0);
-	MAX30102_COPY_DATA(1);
+	switch (measurements) {
+	case 3:
+		MAX30102_COPY_DATA(2);
+	case 2: /* fall-through */
+		MAX30102_COPY_DATA(1);
+	case 1: /* fall-through */
+		MAX30102_COPY_DATA(0);
+		break;
+	default:
+		return -EINVAL;
+	}
 
-	return (ret == 2 * MAX30102_REG_FIFO_DATA_BYTES) ? 0 : -EINVAL;
+	return (ret == measurements * MAX30102_REG_FIFO_DATA_BYTES) ?
+	       0 : -EINVAL;
 }
 
 static irqreturn_t max30102_interrupt_handler(int irq, void *private)
 {
 	struct iio_dev *indio_dev = private;
 	struct max30102_data *data = iio_priv(indio_dev);
+	unsigned int measurements = bitmap_weight(indio_dev->active_scan_mask,
+						  indio_dev->masklength);
 	int ret, cnt = 0;
 
 	mutex_lock(&data->lock);
 
 	while (cnt || (cnt = max30102_fifo_count(data)) > 0) {
-		ret = max30102_read_measurement(data);
+		ret = max30102_read_measurement(data, measurements);
 		if (ret)
 			break;
 
@@ -274,6 +352,29 @@ static int max30102_led_init(struct max30102_data *data)
 	if (ret)
 		return ret;
 
+	if (data->chip_id == max30105) {
+		ret = of_property_read_u32(np,
+			"maxim,green-led-current-microamp", &val);
+		if (ret) {
+			dev_info(dev, "no green-led-current-microamp set\n");
+
+			/* Default to 7 mA green LED */
+			val = 7000;
+		}
+
+		ret = max30102_get_current_idx(val, &reg);
+		if (ret) {
+			dev_err(dev, "invalid green LED current setting %d\n",
+				val);
+			return ret;
+		}
+
+		ret = regmap_write(data->regmap, MAX30105_REG_GREEN_LED_CONFIG,
+				   reg);
+		if (ret)
+			return ret;
+	}
+
 	ret = of_property_read_u32(np, "maxim,ir-led-current-microamp", &val);
 	if (ret) {
 		dev_info(dev, "no ir-led-current-microamp set\n");
@@ -429,10 +530,7 @@ static int max30102_probe(struct i2c_client *client,
 	iio_device_attach_buffer(indio_dev, buffer);
 
 	indio_dev->name = MAX30102_DRV_NAME;
-	indio_dev->channels = max30102_channels;
 	indio_dev->info = &max30102_info;
-	indio_dev->num_channels = ARRAY_SIZE(max30102_channels);
-	indio_dev->available_scan_masks = max30102_scan_masks;
 	indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
 	indio_dev->setup_ops = &max30102_buffer_setup_ops;
 	indio_dev->dev.parent = &client->dev;
@@ -440,10 +538,26 @@ static int max30102_probe(struct i2c_client *client,
 	data = iio_priv(indio_dev);
 	data->indio_dev = indio_dev;
 	data->client = client;
+	data->chip_id = id->driver_data;
 
 	mutex_init(&data->lock);
 	i2c_set_clientdata(client, indio_dev);
 
+	switch (data->chip_id) {
+	case max30105:
+		indio_dev->channels = max30105_channels;
+		indio_dev->num_channels = ARRAY_SIZE(max30105_channels);
+		indio_dev->available_scan_masks = max30105_scan_masks;
+		break;
+	case max30102:
+		indio_dev->channels = max30102_channels;
+		indio_dev->num_channels = ARRAY_SIZE(max30102_channels);
+		indio_dev->available_scan_masks = max30102_scan_masks;
+		break;
+	default:
+		return -ENODEV;
+	}
+
 	data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config);
 	if (IS_ERR(data->regmap)) {
 		dev_err(&client->dev, "regmap initialization failed\n");
@@ -502,13 +616,15 @@ static int max30102_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max30102_id[] = {
-	{ "max30102", 0 },
+	{ "max30102", max30102 },
+	{ "max30105", max30105 },
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, max30102_id);
 
 static const struct of_device_id max30102_dt_ids[] = {
 	{ .compatible = "maxim,max30102" },
+	{ .compatible = "maxim,max30105" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, max30102_dt_ids);
@@ -525,5 +641,5 @@ static struct i2c_driver max30102_driver = {
 module_i2c_driver(max30102_driver);
 
 MODULE_AUTHOR("Matt Ranostay <matt@ranostay.consulting>");
-MODULE_DESCRIPTION("MAX30102 heart rate and pulse oximeter sensor");
+MODULE_DESCRIPTION("MAX30102 heart rate/pulse oximeter and MAX30105 particle sensor driver");
 MODULE_LICENSE("GPL");
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 13/13] dt-bindings: iio: health: Add MAX30105 support to max30102.txt
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (11 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 12/13] iio: health: max30102: Add MAX30105 support Peter Meerwald-Stadler
@ 2017-10-27 19:45 ` Peter Meerwald-Stadler
  2017-11-19 20:35   ` Matt Ranostay
  2017-11-02 14:44 ` [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Jonathan Cameron
  13 siblings, 1 reply; 41+ messages in thread
From: Peter Meerwald-Stadler @ 2017-10-27 19:45 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-iio, Peter Meerwald-Stadler, Matt Ranostay, Rob Herring

Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Matt Ranostay <matt.ranostay@konsulko.com>
Cc: Rob Herring <robh+dt@kernel.org>
---
 Documentation/devicetree/bindings/iio/health/max30102.txt | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/health/max30102.txt b/Documentation/devicetree/bindings/iio/health/max30102.txt
index 8629c18..ef2ca0a 100644
--- a/Documentation/devicetree/bindings/iio/health/max30102.txt
+++ b/Documentation/devicetree/bindings/iio/health/max30102.txt
@@ -1,9 +1,11 @@
 Maxim MAX30102 heart rate and pulse oximeter sensor
+Maxim MAX30105 optical particle-sensing module
 
 * https://datasheets.maximintegrated.com/en/ds/MAX30102.pdf
+* https://datasheets.maximintegrated.com/en/ds/MAX30105.pdf
 
 Required properties:
-  - compatible: must be "maxim,max30102"
+  - compatible: must be "maxim,max30102" or "maxim,max30105"
   - reg: the I2C address of the sensor
   - interrupt-parent: should be the phandle for the interrupt controller
   - interrupts: the sole interrupt generated by the device
@@ -12,8 +14,10 @@ Required properties:
   interrupt client node bindings.
 
 Optional properties:
-  - maxim,red-led-current-microamp: configuration for RED LED current
+  - maxim,red-led-current-microamp: configuration for red LED current
   - maxim,ir-led-current-microamp: configuration for IR LED current
+  - maxim,green-led-current-microamp: configuration for green LED current
+    (max30105 only)
 
     Note that each step is approximately 200 microamps, ranging from 0 uA to
     50800 uA.
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver
  2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
                   ` (12 preceding siblings ...)
  2017-10-27 19:45 ` [PATCH v2 13/13] dt-bindings: iio: health: Add MAX30105 support to max30102.txt Peter Meerwald-Stadler
@ 2017-11-02 14:44 ` Jonathan Cameron
  13 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-02 14:44 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio, Matt Ranostay

On Fri, 27 Oct 2017 21:45:30 +0200
Peter Meerwald-Stadler <pmeerw@pmeerw.net> wrote:

> This patch series reworks the max30102 driver to add support for the
> MAX30105 part (which add a third LED)
> 
> v2:
> * send correct patches, sorry for the mess
> * fix Matt Ranostay's email address
> 
Series looks good to me.

Ideally I'd like Matt to have a look and given where we are in the cycle
(i.e. this one is over for IIO) we have plenty of time.

Thanks,

Jonathan
> 
> patches 1 to 3 are bugfix
> 
> patches 4 to 6 add minor features and cleanup
> 
> patch 8 allows to read the temperature without currently measuring
> other channels
> 
> patches 9 to 11 prepare for adding another LED, more flexibility
> 
> patch 12 adds support for the MAX30105 part
> 
> patch 13 updates devicetree documentation for the MAX30105 part
> 
> Peter Meerwald-Stadler (13):
>   iio: health: max30102: Temperature should be in milli Celsius
>   iio: health: max30102: Fix missing newline in dev_err
>   iio: health: max30102: Remove inconsistent full stop in error
> message iio: health: max30102: Fix mode config values
>   iio: health: max30102: Check retval of powermode function
>   iio: health: max30102: Add check for part ID
>   iio: health: max30102: Introduce intensity channel macro
>   iio: health: max30102: Add power enable parameter to get_temp
> function iio: health: max30102: Introduce indices for LED channels
>   iio: health: max30102: Move mode setting to buffer_postenable
>   iio: health: max30102: Prepare for copying varying number of
>     measurements
>   iio: health: max30102: Add MAX30105 support
>   dt-bindings: iio: health: Add MAX30105 support to max30102.txt
> 
>  .../devicetree/bindings/iio/health/max30102.txt    |   8 +-
>  drivers/iio/health/max30102.c                      | 310
> ++++++++++++++++----- 2 files changed, 241 insertions(+), 77
> deletions(-)
> 


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/13] iio: health: max30102: Fix missing newline in dev_err
  2017-10-27 19:45 ` [PATCH v2 02/13] iio: health: max30102: Fix missing newline in dev_err Peter Meerwald-Stadler
@ 2017-11-19 20:28   ` Matt Ranostay
  2017-11-25 14:05     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:28 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>

Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

> ---
>  drivers/iio/health/max30102.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 147a8c1..62b1b35 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -261,7 +261,7 @@ static int max30102_led_init(struct max30102_data *data)
>
>         ret = max30102_get_current_idx(val, &reg);
>         if (ret) {
> -               dev_err(dev, "invalid IR LED current setting %d", val);
> +               dev_err(dev, "invalid IR LED current setting %d\n", val);
>                 return ret;
>         }
>
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 03/13] iio: health: max30102: Remove inconsistent full stop in error message
  2017-10-27 19:45 ` [PATCH v2 03/13] iio: health: max30102: Remove inconsistent full stop in error message Peter Meerwald-Stadler
@ 2017-11-19 20:28   ` Matt Ranostay
  2017-11-25 14:06     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:28 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>

Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

> ---
>  drivers/iio/health/max30102.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 62b1b35..6ca6182 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -420,7 +420,7 @@ static int max30102_probe(struct i2c_client *client,
>
>         data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config);
>         if (IS_ERR(data->regmap)) {
> -               dev_err(&client->dev, "regmap initialization failed.\n");
> +               dev_err(&client->dev, "regmap initialization failed\n");
>                 return PTR_ERR(data->regmap);
>         }
>         max30102_set_powermode(data, false);
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 13/13] dt-bindings: iio: health: Add MAX30105 support to max30102.txt
  2017-10-27 19:45 ` [PATCH v2 13/13] dt-bindings: iio: health: Add MAX30105 support to max30102.txt Peter Meerwald-Stadler
@ 2017-11-19 20:35   ` Matt Ranostay
  2017-11-25 14:20     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:35 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio, Rob Herring

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> Cc: Rob Herring <robh+dt@kernel.org>

Reviewed-by: Matt Ranostay <matt.ranostay@konsulko.com>

> ---
>  Documentation/devicetree/bindings/iio/health/max30102.txt | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/iio/health/max30102.txt b/Documentation/devicetree/bindings/iio/health/max30102.txt
> index 8629c18..ef2ca0a 100644
> --- a/Documentation/devicetree/bindings/iio/health/max30102.txt
> +++ b/Documentation/devicetree/bindings/iio/health/max30102.txt
> @@ -1,9 +1,11 @@
>  Maxim MAX30102 heart rate and pulse oximeter sensor
> +Maxim MAX30105 optical particle-sensing module
>
>  * https://datasheets.maximintegrated.com/en/ds/MAX30102.pdf
> +* https://datasheets.maximintegrated.com/en/ds/MAX30105.pdf
>
>  Required properties:
> -  - compatible: must be "maxim,max30102"
> +  - compatible: must be "maxim,max30102" or "maxim,max30105"
>    - reg: the I2C address of the sensor
>    - interrupt-parent: should be the phandle for the interrupt controller
>    - interrupts: the sole interrupt generated by the device
> @@ -12,8 +14,10 @@ Required properties:
>    interrupt client node bindings.
>
>  Optional properties:
> -  - maxim,red-led-current-microamp: configuration for RED LED current
> +  - maxim,red-led-current-microamp: configuration for red LED current
>    - maxim,ir-led-current-microamp: configuration for IR LED current
> +  - maxim,green-led-current-microamp: configuration for green LED current
> +    (max30105 only)
>
>      Note that each step is approximately 200 microamps, ranging from 0 uA to
>      50800 uA.
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 07/13] iio: health: max30102: Introduce intensity channel macro
  2017-10-27 19:45 ` [PATCH v2 07/13] iio: health: max30102: Introduce intensity channel macro Peter Meerwald-Stadler
@ 2017-11-19 20:37   ` Matt Ranostay
  2017-11-25 14:12     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:37 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Signed-off-by: Peter Meerwald-Stalder <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>

Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

> ---
>  drivers/iio/health/max30102.c | 44 ++++++++++++++++---------------------------
>  1 file changed, 16 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index c43957e..968b54b 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -106,35 +106,23 @@ static const struct regmap_config max30102_regmap_config = {
>
>  static const unsigned long max30102_scan_masks[] = {0x3, 0};
>
> +#define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
> +               .type = IIO_INTENSITY, \
> +               .channel2 = _mod, \
> +               .modified = 1, \
> +               .scan_index = _si, \
> +               .scan_type = { \
> +                       .sign = 'u', \
> +                       .shift = 8, \
> +                       .realbits = 18, \
> +                       .storagebits = 32, \
> +                       .endianness = IIO_BE, \
> +               }, \
> +       }
> +
>  static const struct iio_chan_spec max30102_channels[] = {
> -       {
> -               .type = IIO_INTENSITY,
> -               .channel2 = IIO_MOD_LIGHT_RED,
> -               .modified = 1,
> -
> -               .scan_index = 0,
> -               .scan_type = {
> -                       .sign = 'u',
> -                       .shift = 8,
> -                       .realbits = 18,
> -                       .storagebits = 32,
> -                       .endianness = IIO_BE,
> -               },
> -       },
> -       {
> -               .type = IIO_INTENSITY,
> -               .channel2 = IIO_MOD_LIGHT_IR,
> -               .modified = 1,
> -
> -               .scan_index = 1,
> -               .scan_type = {
> -                       .sign = 'u',
> -                       .shift = 8,
> -                       .realbits = 18,
> -                       .storagebits = 32,
> -                       .endianness = IIO_BE,
> -               },
> -       },
> +       MAX30102_INTENSITY_CHANNEL(0, IIO_MOD_LIGHT_RED),
> +       MAX30102_INTENSITY_CHANNEL(1, IIO_MOD_LIGHT_IR),
>         {
>                 .type = IIO_TEMP,
>                 .info_mask_separate =
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 06/13] iio: health: max30102: Add check for part ID
  2017-10-27 19:45 ` [PATCH v2 06/13] iio: health: max30102: Add check for part ID Peter Meerwald-Stadler
@ 2017-11-19 20:38   ` Matt Ranostay
  2017-11-25 14:11     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:38 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>


Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

> ---
>  drivers/iio/health/max30102.c | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 389a483..c43957e 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -32,6 +32,7 @@
>
>  #define MAX30102_REGMAP_NAME   "max30102_regmap"
>  #define MAX30102_DRV_NAME      "max30102"
> +#define MAX30102_PART_NUMBER   0x15
>
>  #define MAX30102_REG_INT_STATUS                        0x00
>  #define MAX30102_REG_INT_STATUS_PWR_RDY                BIT(0)
> @@ -83,6 +84,9 @@
>  #define MAX30102_REG_TEMP_INTEGER              0x1f
>  #define MAX30102_REG_TEMP_FRACTION             0x20
>
> +#define MAX30102_REG_REV_ID                    0xfe
> +#define MAX30102_REG_PART_ID                   0xff
> +
>  struct max30102_data {
>         struct i2c_client *client;
>         struct iio_dev *indio_dev;
> @@ -391,6 +395,7 @@ static int max30102_probe(struct i2c_client *client,
>         struct iio_buffer *buffer;
>         struct iio_dev *indio_dev;
>         int ret;
> +       unsigned int reg;
>
>         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
>         if (!indio_dev)
> @@ -424,6 +429,19 @@ static int max30102_probe(struct i2c_client *client,
>                 return PTR_ERR(data->regmap);
>         }
>
> +       /* check part ID */
> +       ret = regmap_read(data->regmap, MAX30102_REG_PART_ID, &reg);
> +       if (ret)
> +               return ret;
> +       if (reg != MAX30102_PART_NUMBER)
> +               return -ENODEV;
> +
> +       /* show revision ID */
> +       ret = regmap_read(data->regmap, MAX30102_REG_REV_ID, &reg);
> +       if (ret)
> +               return ret;
> +       dev_dbg(&client->dev, "max3010x revision %02x\n", reg);
> +
>         ret = max30102_set_powermode(data, false);
>         if (ret)
>                 return ret;
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 08/13] iio: health: max30102: Add power enable parameter to get_temp function
  2017-10-27 19:45 ` [PATCH v2 08/13] iio: health: max30102: Add power enable parameter to get_temp function Peter Meerwald-Stadler
@ 2017-11-19 20:41   ` Matt Ranostay
  2017-11-25 14:15     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:41 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Chip must not be in shutdown for reading temperature, so briefly leave
> shutdown if buffer is not already running
>

Looks good to me. I assume there is no setup delay required for power on though?


Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>


> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> ---
>  drivers/iio/health/max30102.c | 36 +++++++++++++++++++++++-------------
>  1 file changed, 23 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 968b54b..520d905 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -321,20 +321,31 @@ static int max30102_read_temp(struct max30102_data *data, int *val)
>         return 0;
>  }
>
> -static int max30102_get_temp(struct max30102_data *data, int *val)
> +static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
>  {
>         int ret;
>
> +       if (en) {
> +               ret = max30102_set_powermode(data, true);
> +               if (ret)
> +                       return ret;
> +       }
> +
>         /* start acquisition */
>         ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
>                                  MAX30102_REG_TEMP_CONFIG_TEMP_EN,
>                                  MAX30102_REG_TEMP_CONFIG_TEMP_EN);
>         if (ret)
> -               return ret;
> +               goto out;
>
>         msleep(35);
> +       ret = max30102_read_temp(data, val);
> +
> +out:
> +       if (en)
> +               max30102_set_powermode(data, false);
>
> -       return max30102_read_temp(data, val);
> +       return ret;
>  }
>
>  static int max30102_read_raw(struct iio_dev *indio_dev,
> @@ -347,20 +358,19 @@ static int max30102_read_raw(struct iio_dev *indio_dev,
>         switch (mask) {
>         case IIO_CHAN_INFO_RAW:
>                 /*
> -                * Temperature reading can only be acquired while engine
> -                * is running
> +                * Temperature reading can only be acquired when not in
> +                * shutdown; leave shutdown briefly when buffer not running
>                  */
>                 mutex_lock(&indio_dev->mlock);
> -
>                 if (!iio_buffer_enabled(indio_dev))
> -                       ret = -EBUSY;
> -               else {
> -                       ret = max30102_get_temp(data, val);
> -                       if (!ret)
> -                               ret = IIO_VAL_INT;
> -               }
> -
> +                       ret = max30102_get_temp(data, val, true);
> +               else
> +                       ret = max30102_get_temp(data, val, false);
>                 mutex_unlock(&indio_dev->mlock);
> +               if (ret)
> +                       return ret;
> +
> +               ret = IIO_VAL_INT;
>                 break;
>         case IIO_CHAN_INFO_SCALE:
>                 *val = 1000;  /* 62.5 */
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 09/13] iio: health: max30102: Introduce indices for LED channels
  2017-10-27 19:45 ` [PATCH v2 09/13] iio: health: max30102: Introduce indices for LED channels Peter Meerwald-Stadler
@ 2017-11-19 20:42   ` Matt Ranostay
  2017-11-25 14:16     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:42 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>

Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

> ---
>  drivers/iio/health/max30102.c | 14 +++++++++++---
>  1 file changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 520d905..37176c2 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -34,6 +34,11 @@
>  #define MAX30102_DRV_NAME      "max30102"
>  #define MAX30102_PART_NUMBER   0x15
>
> +enum max3012_led_idx {
> +       MAX30102_LED_RED,
> +       MAX30102_LED_IR,
> +};
> +
>  #define MAX30102_REG_INT_STATUS                        0x00
>  #define MAX30102_REG_INT_STATUS_PWR_RDY                BIT(0)
>  #define MAX30102_REG_INT_STATUS_PROX_INT       BIT(4)
> @@ -104,7 +109,10 @@ static const struct regmap_config max30102_regmap_config = {
>         .val_bits = 8,
>  };
>
> -static const unsigned long max30102_scan_masks[] = {0x3, 0};
> +static const unsigned long max30102_scan_masks[] = {
> +       BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR),
> +       0
> +};
>
>  #define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
>                 .type = IIO_INTENSITY, \
> @@ -121,8 +129,8 @@ static const unsigned long max30102_scan_masks[] = {0x3, 0};
>         }
>
>  static const struct iio_chan_spec max30102_channels[] = {
> -       MAX30102_INTENSITY_CHANNEL(0, IIO_MOD_LIGHT_RED),
> -       MAX30102_INTENSITY_CHANNEL(1, IIO_MOD_LIGHT_IR),
> +       MAX30102_INTENSITY_CHANNEL(MAX30102_LED_RED, IIO_MOD_LIGHT_RED),
> +       MAX30102_INTENSITY_CHANNEL(MAX30102_LED_IR, IIO_MOD_LIGHT_IR),
>         {
>                 .type = IIO_TEMP,
>                 .info_mask_separate =
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 05/13] iio: health: max30102: Check retval of powermode function
  2017-10-27 19:45 ` [PATCH v2 05/13] iio: health: max30102: Check retval of powermode function Peter Meerwald-Stadler
@ 2017-11-19 20:43   ` Matt Ranostay
  2017-11-25 14:08     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:43 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>

Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

> ---
>  drivers/iio/health/max30102.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 13d5312..389a483 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -423,7 +423,10 @@ static int max30102_probe(struct i2c_client *client,
>                 dev_err(&client->dev, "regmap initialization failed\n");
>                 return PTR_ERR(data->regmap);
>         }
> -       max30102_set_powermode(data, false);
> +
> +       ret = max30102_set_powermode(data, false);
> +       if (ret)
> +               return ret;
>
>         ret = max30102_chip_init(data);
>         if (ret)
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 04/13] iio: health: max30102: Fix mode config values
  2017-10-27 19:45 ` [PATCH v2 04/13] iio: health: max30102: Fix mode config values Peter Meerwald-Stadler
@ 2017-11-19 20:46   ` Matt Ranostay
  2017-11-25 14:07     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:46 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Table 4 of the datasheet specifies the mode control, these are not
> individual bits; add multi LED mode
>
> Add multi-LED mode and fix MODE_MASK (3 bits wide, not 2)

Yeah this much cleaner than the macros I had defined

Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

>
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> ---
>  drivers/iio/health/max30102.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 6ca6182..13d5312 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -60,9 +60,10 @@
>  #define MAX30102_REG_FIFO_CONFIG_AFULL         BIT(0)
>
>  #define MAX30102_REG_MODE_CONFIG               0x09
> -#define MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN  BIT(0)
> -#define MAX30102_REG_MODE_CONFIG_MODE_HR_EN    BIT(1)
> -#define MAX30102_REG_MODE_CONFIG_MODE_MASK     0x03
> +#define MAX30102_REG_MODE_CONFIG_MODE_HR       0x02 /* red LED */
> +#define MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2  0x03 /* red + IR LED */
> +#define MAX30102_REG_MODE_CONFIG_MODE_MULTI    0x07 /* multi-LED mode */
> +#define MAX30102_REG_MODE_CONFIG_MODE_MASK     GENMASK(2, 0)
>  #define MAX30102_REG_MODE_CONFIG_PWR           BIT(7)
>
>  #define MAX30102_REG_SPO2_CONFIG               0x0a
> @@ -287,11 +288,10 @@ static int max30102_chip_init(struct max30102_data *data)
>         if (ret)
>                 return ret;
>
> -       /* enable SPO2 mode */
> +       /* enable HR + SPO2 mode */
>         ret = regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
>                                  MAX30102_REG_MODE_CONFIG_MODE_MASK,
> -                                MAX30102_REG_MODE_CONFIG_MODE_HR_EN |
> -                                MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN);
> +                                MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2);
>         if (ret)
>                 return ret;
>
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 11/13] iio: health: max30102: Prepare for copying varying number of measurements
  2017-10-27 19:45 ` [PATCH v2 11/13] iio: health: max30102: Prepare for copying varying number of measurements Peter Meerwald-Stadler
@ 2017-11-19 20:52   ` Matt Ranostay
  2017-11-25 14:18     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:52 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Current code assumes always 2 measurements (6 bytes) have to be copied,
> prepare for more flexibility


Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

>
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> ---
>  drivers/iio/health/max30102.c | 15 ++++++++++-----
>  1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 1c7fe63..86058f0 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -58,7 +58,7 @@ enum max3012_led_idx {
>  #define MAX30102_REG_FIFO_OVR_CTR              0x05
>  #define MAX30102_REG_FIFO_RD_PTR               0x06
>  #define MAX30102_REG_FIFO_DATA                 0x07
> -#define MAX30102_REG_FIFO_DATA_ENTRY_LEN       6
> +#define MAX30102_REG_FIFO_DATA_BYTES           3
>
>  #define MAX30102_REG_FIFO_CONFIG               0x08
>  #define MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES  BIT(1)
> @@ -198,6 +198,11 @@ static inline int max30102_fifo_count(struct max30102_data *data)
>         return 0;
>  }
>
> +#define MAX30102_COPY_DATA(i) \
> +       memcpy(&data->processed_buffer[(i)], \
> +              &buffer[(i) * MAX30102_REG_FIFO_DATA_BYTES], \
> +              MAX30102_REG_FIFO_DATA_BYTES)
> +
>  static int max30102_read_measurement(struct max30102_data *data)
>  {
>         int ret;
> @@ -205,13 +210,13 @@ static int max30102_read_measurement(struct max30102_data *data)
>
>         ret = i2c_smbus_read_i2c_block_data(data->client,
>                                             MAX30102_REG_FIFO_DATA,
> -                                           MAX30102_REG_FIFO_DATA_ENTRY_LEN,
> +                                           2 * MAX30102_REG_FIFO_DATA_BYTES,
>                                             buffer);
>
> -       memcpy(&data->processed_buffer[0], &buffer[0], 3);
> -       memcpy(&data->processed_buffer[1], &buffer[3], 3);
> +       MAX30102_COPY_DATA(0);
> +       MAX30102_COPY_DATA(1);
>
> -       return (ret == MAX30102_REG_FIFO_DATA_ENTRY_LEN) ? 0 : -EINVAL;
> +       return (ret == 2 * MAX30102_REG_FIFO_DATA_BYTES) ? 0 : -EINVAL;
>  }
>
>  static irqreturn_t max30102_interrupt_handler(int irq, void *private)
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 10/13] iio: health: max30102: Move mode setting to buffer_postenable
  2017-10-27 19:45 ` [PATCH v2 10/13] iio: health: max30102: Move mode setting to buffer_postenable Peter Meerwald-Stadler
@ 2017-11-19 20:56   ` Matt Ranostay
  2017-11-25 14:17     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 20:56 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> Move the programming of the mode setting from init() to
> buffer_postenable()
>
> Split out a separate function to
> only update the power/shutdown bit
>
> This changes permits to more easily implement different
> modes of measurements in further patches
>
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>

Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

> ---
>  drivers/iio/health/max30102.c | 44 +++++++++++++++++++++++++++----------------
>  1 file changed, 28 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 37176c2..1c7fe63 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -66,6 +66,7 @@ enum max3012_led_idx {
>  #define MAX30102_REG_FIFO_CONFIG_AFULL         BIT(0)
>
>  #define MAX30102_REG_MODE_CONFIG               0x09
> +#define MAX30102_REG_MODE_CONFIG_MODE_NONE     0x00
>  #define MAX30102_REG_MODE_CONFIG_MODE_HR       0x02 /* red LED */
>  #define MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2  0x03 /* red + IR LED */
>  #define MAX30102_REG_MODE_CONFIG_MODE_MULTI    0x07 /* multi-LED mode */
> @@ -139,25 +140,41 @@ static const struct iio_chan_spec max30102_channels[] = {
>         },
>  };
>
> -static int max30102_set_powermode(struct max30102_data *data, bool state)
> +static int max30102_set_power(struct max30102_data *data, bool en)
>  {
>         return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
>                                   MAX30102_REG_MODE_CONFIG_PWR,
> -                                 state ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
> +                                 en ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
> +}
> +
> +static int max30102_set_powermode(struct max30102_data *data, u8 mode, bool en)
> +{
> +       u8 reg = mode;
> +
> +       if (!en)
> +               reg |= MAX30102_REG_MODE_CONFIG_PWR;
> +
> +       return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
> +                                 MAX30102_REG_MODE_CONFIG_PWR |
> +                                 MAX30102_REG_MODE_CONFIG_MODE_MASK, reg);
>  }
>
>  static int max30102_buffer_postenable(struct iio_dev *indio_dev)
>  {
>         struct max30102_data *data = iio_priv(indio_dev);
> +       u8 reg;
> +
> +       reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
>
> -       return max30102_set_powermode(data, true);
> +       return max30102_set_powermode(data, reg, true);
>  }
>
>  static int max30102_buffer_predisable(struct iio_dev *indio_dev)
>  {
>         struct max30102_data *data = iio_priv(indio_dev);
>
> -       return max30102_set_powermode(data, false);
> +       return max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
> +                                     false);
>  }
>
>  static const struct iio_buffer_setup_ops max30102_buffer_setup_ops = {
> @@ -278,7 +295,7 @@ static int max30102_chip_init(struct max30102_data *data)
>         if (ret)
>                 return ret;
>
> -       /* enable 18-bit HR + SPO2 readings at 400Hz */
> +       /* configure 18-bit HR + SpO2 readings at 400Hz */
>         ret = regmap_write(data->regmap, MAX30102_REG_SPO2_CONFIG,
>                                 (MAX30102_REG_SPO2_CONFIG_ADC_4096_STEPS
>                                  << MAX30102_REG_SPO2_CONFIG_ADC_MASK_SHIFT) |
> @@ -288,13 +305,6 @@ static int max30102_chip_init(struct max30102_data *data)
>         if (ret)
>                 return ret;
>
> -       /* enable HR + SPO2 mode */
> -       ret = regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
> -                                MAX30102_REG_MODE_CONFIG_MODE_MASK,
> -                                MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2);
> -       if (ret)
> -               return ret;
> -
>         /* average 4 samples + generate FIFO interrupt */
>         ret = regmap_write(data->regmap, MAX30102_REG_FIFO_CONFIG,
>                                 (MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES
> @@ -334,7 +344,7 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
>         int ret;
>
>         if (en) {
> -               ret = max30102_set_powermode(data, true);
> +               ret = max30102_set_power(data, true);
>                 if (ret)
>                         return ret;
>         }
> @@ -351,7 +361,7 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
>
>  out:
>         if (en)
> -               max30102_set_powermode(data, false);
> +               max30102_set_power(data, false);
>
>         return ret;
>  }
> @@ -448,7 +458,9 @@ static int max30102_probe(struct i2c_client *client,
>                 return ret;
>         dev_dbg(&client->dev, "max3010x revision %02x\n", reg);
>
> -       ret = max30102_set_powermode(data, false);
> +       /* clear mode setting, chip shutdown */
> +       ret = max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
> +                                    false);
>         if (ret)
>                 return ret;
>
> @@ -479,7 +491,7 @@ static int max30102_remove(struct i2c_client *client)
>         struct max30102_data *data = iio_priv(indio_dev);
>
>         iio_device_unregister(indio_dev);
> -       max30102_set_powermode(data, false);
> +       max30102_set_power(data, false);
>
>         return 0;
>  }
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 12/13] iio: health: max30102: Add MAX30105 support
  2017-10-27 19:45 ` [PATCH v2 12/13] iio: health: max30102: Add MAX30105 support Peter Meerwald-Stadler
@ 2017-11-19 21:00   ` Matt Ranostay
  2017-11-25 14:19     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 21:00 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> The Maxim MAX30105 part adds a third LED (green) and uses a multi-LED
> measuring mode producing three measurements
>
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>

Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

> ---
>  drivers/iio/health/max30102.c | 144 ++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 130 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 86058f0..15ccadc 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -3,6 +3,9 @@
>   *
>   * Copyright (C) 2017 Matt Ranostay <matt@ranostay.consulting>
>   *
> + * Support for MAX30105 optical particle sensor
> + * Copyright (C) 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> + *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License as published by
>   * the Free Software Foundation; either version 2 of the License, or
> @@ -13,6 +16,7 @@
>   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>   * GNU General Public License for more details.
>   *
> + * 7-bit I2C chip address: 0x57
>   * TODO: proximity power saving feature
>   */
>
> @@ -34,9 +38,15 @@
>  #define MAX30102_DRV_NAME      "max30102"
>  #define MAX30102_PART_NUMBER   0x15
>
> +enum max30102_chip_id {
> +       max30102,
> +       max30105,
> +};
> +
>  enum max3012_led_idx {
>         MAX30102_LED_RED,
>         MAX30102_LED_IR,
> +       MAX30105_LED_GREEN,
>  };
>
>  #define MAX30102_REG_INT_STATUS                        0x00
> @@ -73,6 +83,11 @@ enum max3012_led_idx {
>  #define MAX30102_REG_MODE_CONFIG_MODE_MASK     GENMASK(2, 0)
>  #define MAX30102_REG_MODE_CONFIG_PWR           BIT(7)
>
> +#define MAX30102_REG_MODE_CONTROL_SLOT21       0x11 /* multi-LED control */
> +#define MAX30102_REG_MODE_CONTROL_SLOT43       0x12
> +#define MAX30102_REG_MODE_CONTROL_SLOT_MASK    (GENMASK(6, 4) | GENMASK(2, 0))
> +#define MAX30102_REG_MODE_CONTROL_SLOT_SHIFT   4

I assume slot is some time multiplexing of the LEDs?

> +
>  #define MAX30102_REG_SPO2_CONFIG               0x0a
>  #define MAX30102_REG_SPO2_CONFIG_PULSE_411_US  0x03
>  #define MAX30102_REG_SPO2_CONFIG_SR_400HZ      0x03
> @@ -83,6 +98,7 @@ enum max3012_led_idx {
>
>  #define MAX30102_REG_RED_LED_CONFIG            0x0c
>  #define MAX30102_REG_IR_LED_CONFIG             0x0d
> +#define MAX30105_REG_GREEN_LED_CONFIG          0x0e
>
>  #define MAX30102_REG_TEMP_CONFIG               0x21
>  #define MAX30102_REG_TEMP_CONFIG_TEMP_EN       BIT(0)
> @@ -98,9 +114,10 @@ struct max30102_data {
>         struct iio_dev *indio_dev;
>         struct mutex lock;
>         struct regmap *regmap;
> +       enum max30102_chip_id chip_id;
>
> -       u8 buffer[8];
> -       __be32 processed_buffer[2]; /* 2 x 18-bit (padded to 32-bits) */
> +       u8 buffer[12];
> +       __be32 processed_buffer[3]; /* 3 x 18-bit (padded to 32-bits) */
>  };
>
>  static const struct regmap_config max30102_regmap_config = {
> @@ -115,6 +132,13 @@ static const unsigned long max30102_scan_masks[] = {
>         0
>  };
>
> +static const unsigned long max30105_scan_masks[] = {
> +       BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR),
> +       BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR) |
> +               BIT(MAX30105_LED_GREEN),
> +       0
> +};
> +
>  #define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
>                 .type = IIO_INTENSITY, \
>                 .channel2 = _mod, \
> @@ -140,6 +164,18 @@ static const struct iio_chan_spec max30102_channels[] = {
>         },
>  };
>
> +static const struct iio_chan_spec max30105_channels[] = {
> +       MAX30102_INTENSITY_CHANNEL(MAX30102_LED_RED, IIO_MOD_LIGHT_RED),
> +       MAX30102_INTENSITY_CHANNEL(MAX30102_LED_IR, IIO_MOD_LIGHT_IR),
> +       MAX30102_INTENSITY_CHANNEL(MAX30105_LED_GREEN, IIO_MOD_LIGHT_GREEN),
> +       {
> +               .type = IIO_TEMP,
> +               .info_mask_separate =
> +                       BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
> +               .scan_index = -1,
> +       },
> +};
> +
>  static int max30102_set_power(struct max30102_data *data, bool en)
>  {
>         return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
> @@ -159,12 +195,40 @@ static int max30102_set_powermode(struct max30102_data *data, u8 mode, bool en)
>                                   MAX30102_REG_MODE_CONFIG_MODE_MASK, reg);
>  }
>
> +#define MAX30102_MODE_CONTROL_LED_SLOTS(slot2, slot1) \
> +       ((slot2 << MAX30102_REG_MODE_CONTROL_SLOT_SHIFT) | slot1)
> +
>  static int max30102_buffer_postenable(struct iio_dev *indio_dev)
>  {
>         struct max30102_data *data = iio_priv(indio_dev);
> +       int ret;
>         u8 reg;
>
> -       reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
> +       switch (*indio_dev->active_scan_mask) {
> +       case BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR):
> +               reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
> +               break;
> +       case BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR) |
> +            BIT(MAX30105_LED_GREEN):
> +               ret = regmap_update_bits(data->regmap,
> +                                        MAX30102_REG_MODE_CONTROL_SLOT21,
> +                                        MAX30102_REG_MODE_CONTROL_SLOT_MASK,
> +                                        MAX30102_MODE_CONTROL_LED_SLOTS(2, 1));
> +               if (ret)
> +                       return ret;
> +
> +               ret = regmap_update_bits(data->regmap,
> +                                        MAX30102_REG_MODE_CONTROL_SLOT43,
> +                                        MAX30102_REG_MODE_CONTROL_SLOT_MASK,
> +                                        MAX30102_MODE_CONTROL_LED_SLOTS(0, 3));
> +               if (ret)
> +                       return ret;
> +
> +               reg = MAX30102_REG_MODE_CONFIG_MODE_MULTI;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
>
>         return max30102_set_powermode(data, reg, true);
>  }
> @@ -203,32 +267,46 @@ static inline int max30102_fifo_count(struct max30102_data *data)
>                &buffer[(i) * MAX30102_REG_FIFO_DATA_BYTES], \
>                MAX30102_REG_FIFO_DATA_BYTES)
>
> -static int max30102_read_measurement(struct max30102_data *data)
> +static int max30102_read_measurement(struct max30102_data *data,
> +                                    unsigned int measurements)
>  {
>         int ret;
>         u8 *buffer = (u8 *) &data->buffer;
>
>         ret = i2c_smbus_read_i2c_block_data(data->client,
>                                             MAX30102_REG_FIFO_DATA,
> -                                           2 * MAX30102_REG_FIFO_DATA_BYTES,
> +                                           measurements *
> +                                           MAX30102_REG_FIFO_DATA_BYTES,
>                                             buffer);
>
> -       MAX30102_COPY_DATA(0);
> -       MAX30102_COPY_DATA(1);
> +       switch (measurements) {
> +       case 3:
> +               MAX30102_COPY_DATA(2);
> +       case 2: /* fall-through */
> +               MAX30102_COPY_DATA(1);
> +       case 1: /* fall-through */
> +               MAX30102_COPY_DATA(0);
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
>
> -       return (ret == 2 * MAX30102_REG_FIFO_DATA_BYTES) ? 0 : -EINVAL;
> +       return (ret == measurements * MAX30102_REG_FIFO_DATA_BYTES) ?
> +              0 : -EINVAL;
>  }
>
>  static irqreturn_t max30102_interrupt_handler(int irq, void *private)
>  {
>         struct iio_dev *indio_dev = private;
>         struct max30102_data *data = iio_priv(indio_dev);
> +       unsigned int measurements = bitmap_weight(indio_dev->active_scan_mask,
> +                                                 indio_dev->masklength);
>         int ret, cnt = 0;
>
>         mutex_lock(&data->lock);
>
>         while (cnt || (cnt = max30102_fifo_count(data)) > 0) {
> -               ret = max30102_read_measurement(data);
> +               ret = max30102_read_measurement(data, measurements);
>                 if (ret)
>                         break;
>
> @@ -274,6 +352,29 @@ static int max30102_led_init(struct max30102_data *data)
>         if (ret)
>                 return ret;
>
> +       if (data->chip_id == max30105) {
> +               ret = of_property_read_u32(np,
> +                       "maxim,green-led-current-microamp", &val);
> +               if (ret) {
> +                       dev_info(dev, "no green-led-current-microamp set\n");
> +
> +                       /* Default to 7 mA green LED */
> +                       val = 7000;
> +               }
> +
> +               ret = max30102_get_current_idx(val, &reg);
> +               if (ret) {
> +                       dev_err(dev, "invalid green LED current setting %d\n",
> +                               val);
> +                       return ret;
> +               }
> +
> +               ret = regmap_write(data->regmap, MAX30105_REG_GREEN_LED_CONFIG,
> +                                  reg);
> +               if (ret)
> +                       return ret;
> +       }
> +
>         ret = of_property_read_u32(np, "maxim,ir-led-current-microamp", &val);
>         if (ret) {
>                 dev_info(dev, "no ir-led-current-microamp set\n");
> @@ -429,10 +530,7 @@ static int max30102_probe(struct i2c_client *client,
>         iio_device_attach_buffer(indio_dev, buffer);
>
>         indio_dev->name = MAX30102_DRV_NAME;
> -       indio_dev->channels = max30102_channels;
>         indio_dev->info = &max30102_info;
> -       indio_dev->num_channels = ARRAY_SIZE(max30102_channels);
> -       indio_dev->available_scan_masks = max30102_scan_masks;
>         indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
>         indio_dev->setup_ops = &max30102_buffer_setup_ops;
>         indio_dev->dev.parent = &client->dev;
> @@ -440,10 +538,26 @@ static int max30102_probe(struct i2c_client *client,
>         data = iio_priv(indio_dev);
>         data->indio_dev = indio_dev;
>         data->client = client;
> +       data->chip_id = id->driver_data;
>
>         mutex_init(&data->lock);
>         i2c_set_clientdata(client, indio_dev);
>
> +       switch (data->chip_id) {
> +       case max30105:
> +               indio_dev->channels = max30105_channels;
> +               indio_dev->num_channels = ARRAY_SIZE(max30105_channels);
> +               indio_dev->available_scan_masks = max30105_scan_masks;
> +               break;
> +       case max30102:
> +               indio_dev->channels = max30102_channels;
> +               indio_dev->num_channels = ARRAY_SIZE(max30102_channels);
> +               indio_dev->available_scan_masks = max30102_scan_masks;
> +               break;
> +       default:
> +               return -ENODEV;
> +       }
> +
>         data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config);
>         if (IS_ERR(data->regmap)) {
>                 dev_err(&client->dev, "regmap initialization failed\n");
> @@ -502,13 +616,15 @@ static int max30102_remove(struct i2c_client *client)
>  }
>
>  static const struct i2c_device_id max30102_id[] = {
> -       { "max30102", 0 },
> +       { "max30102", max30102 },
> +       { "max30105", max30105 },
>         {}
>  };
>  MODULE_DEVICE_TABLE(i2c, max30102_id);
>
>  static const struct of_device_id max30102_dt_ids[] = {
>         { .compatible = "maxim,max30102" },
> +       { .compatible = "maxim,max30105" },
>         { }
>  };
>  MODULE_DEVICE_TABLE(of, max30102_dt_ids);
> @@ -525,5 +641,5 @@ static struct i2c_driver max30102_driver = {
>  module_i2c_driver(max30102_driver);
>
>  MODULE_AUTHOR("Matt Ranostay <matt@ranostay.consulting>");
> -MODULE_DESCRIPTION("MAX30102 heart rate and pulse oximeter sensor");
> +MODULE_DESCRIPTION("MAX30102 heart rate/pulse oximeter and MAX30105 particle sensor driver");
>  MODULE_LICENSE("GPL");
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 01/13] iio: health: max30102: Temperature should be in milli Celsius
  2017-10-27 19:45 ` [PATCH v2 01/13] iio: health: max30102: Temperature should be in milli Celsius Peter Meerwald-Stadler
@ 2017-11-19 21:09   ` Matt Ranostay
  2017-11-25 14:04     ` Jonathan Cameron
  0 siblings, 1 reply; 41+ messages in thread
From: Matt Ranostay @ 2017-11-19 21:09 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: Jonathan Cameron, linux-iio

On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
<pmeerw@pmeerw.net> wrote:
> As per ABI temperature should be in milli Celsius after scaling,
> not Celsius

Good catch...Thanks

Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

>
> Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> ---
>  drivers/iio/health/max30102.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> index 203ffb9..147a8c1 100644
> --- a/drivers/iio/health/max30102.c
> +++ b/drivers/iio/health/max30102.c
> @@ -371,7 +371,7 @@ static int max30102_read_raw(struct iio_dev *indio_dev,
>                 mutex_unlock(&indio_dev->mlock);
>                 break;
>         case IIO_CHAN_INFO_SCALE:
> -               *val = 1;  /* 0.0625 */
> +               *val = 1000;  /* 62.5 */
>                 *val2 = 16;
>                 ret = IIO_VAL_FRACTIONAL;
>                 break;
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 01/13] iio: health: max30102: Temperature should be in milli Celsius
  2017-11-19 21:09   ` Matt Ranostay
@ 2017-11-25 14:04     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:04 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 13:09:34 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > As per ABI temperature should be in milli Celsius after scaling,
> > not Celsius  
> 
> Good catch...Thanks
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
Applied to the fixes-togreg branch of iio.git and marked for stable.

I've also added a brief not to emphasise that is breaking the ABI
hence I want it fixed in stable...  (just hammering the point
home ;)

Thanks

Jonathan
> 
> >
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> > ---
> >  drivers/iio/health/max30102.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 203ffb9..147a8c1 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -371,7 +371,7 @@ static int max30102_read_raw(struct iio_dev *indio_dev,
> >                 mutex_unlock(&indio_dev->mlock);
> >                 break;
> >         case IIO_CHAN_INFO_SCALE:
> > -               *val = 1;  /* 0.0625 */
> > +               *val = 1000;  /* 62.5 */
> >                 *val2 = 16;
> >                 ret = IIO_VAL_FRACTIONAL;
> >                 break;
> > --
> > 2.7.4
> >  


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/13] iio: health: max30102: Fix missing newline in dev_err
  2017-11-19 20:28   ` Matt Ranostay
@ 2017-11-25 14:05     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:05 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:28:08 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>  
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

Applied to the togreg branch of iio.git.

Thanks,

Jonathan
> 
> > ---
> >  drivers/iio/health/max30102.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 147a8c1..62b1b35 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -261,7 +261,7 @@ static int max30102_led_init(struct max30102_data *data)
> >
> >         ret = max30102_get_current_idx(val, &reg);
> >         if (ret) {
> > -               dev_err(dev, "invalid IR LED current setting %d", val);
> > +               dev_err(dev, "invalid IR LED current setting %d\n", val);
> >                 return ret;
> >         }
> >
> > --
> > 2.7.4
> >  


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 03/13] iio: health: max30102: Remove inconsistent full stop in error message
  2017-11-19 20:28   ` Matt Ranostay
@ 2017-11-25 14:06     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:06 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:28:46 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>  
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
Applied.
> 
> > ---
> >  drivers/iio/health/max30102.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 62b1b35..6ca6182 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -420,7 +420,7 @@ static int max30102_probe(struct i2c_client *client,
> >
> >         data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config);
> >         if (IS_ERR(data->regmap)) {
> > -               dev_err(&client->dev, "regmap initialization failed.\n");
> > +               dev_err(&client->dev, "regmap initialization failed\n");
> >                 return PTR_ERR(data->regmap);
> >         }
> >         max30102_set_powermode(data, false);
> > --
> > 2.7.4
> >  
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 04/13] iio: health: max30102: Fix mode config values
  2017-11-19 20:46   ` Matt Ranostay
@ 2017-11-25 14:07     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:07 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:46:40 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Table 4 of the datasheet specifies the mode control, these are not
> > individual bits; add multi LED mode
> >
> > Add multi-LED mode and fix MODE_MASK (3 bits wide, not 2)  
> 
> Yeah this much cleaner than the macros I had defined
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
> 
Applied.
> >
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> > ---
> >  drivers/iio/health/max30102.c | 12 ++++++------
> >  1 file changed, 6 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 6ca6182..13d5312 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -60,9 +60,10 @@
> >  #define MAX30102_REG_FIFO_CONFIG_AFULL         BIT(0)
> >
> >  #define MAX30102_REG_MODE_CONFIG               0x09
> > -#define MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN  BIT(0)
> > -#define MAX30102_REG_MODE_CONFIG_MODE_HR_EN    BIT(1)
> > -#define MAX30102_REG_MODE_CONFIG_MODE_MASK     0x03
> > +#define MAX30102_REG_MODE_CONFIG_MODE_HR       0x02 /* red LED */
> > +#define MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2  0x03 /* red + IR LED */
> > +#define MAX30102_REG_MODE_CONFIG_MODE_MULTI    0x07 /* multi-LED mode */
> > +#define MAX30102_REG_MODE_CONFIG_MODE_MASK     GENMASK(2, 0)
> >  #define MAX30102_REG_MODE_CONFIG_PWR           BIT(7)
> >
> >  #define MAX30102_REG_SPO2_CONFIG               0x0a
> > @@ -287,11 +288,10 @@ static int max30102_chip_init(struct max30102_data *data)
> >         if (ret)
> >                 return ret;
> >
> > -       /* enable SPO2 mode */
> > +       /* enable HR + SPO2 mode */
> >         ret = regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
> >                                  MAX30102_REG_MODE_CONFIG_MODE_MASK,
> > -                                MAX30102_REG_MODE_CONFIG_MODE_HR_EN |
> > -                                MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN);
> > +                                MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2);
> >         if (ret)
> >                 return ret;
> >
> > --
> > 2.7.4
> >  
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 05/13] iio: health: max30102: Check retval of powermode function
  2017-11-19 20:43   ` Matt Ranostay
@ 2017-11-25 14:08     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:08 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:43:09 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>  
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
Applied.
> 
> > ---
> >  drivers/iio/health/max30102.c | 5 ++++-
> >  1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 13d5312..389a483 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -423,7 +423,10 @@ static int max30102_probe(struct i2c_client *client,
> >                 dev_err(&client->dev, "regmap initialization failed\n");
> >                 return PTR_ERR(data->regmap);
> >         }
> > -       max30102_set_powermode(data, false);
> > +
> > +       ret = max30102_set_powermode(data, false);
> > +       if (ret)
> > +               return ret;
> >
> >         ret = max30102_chip_init(data);
> >         if (ret)
> > --
> > 2.7.4
> >  
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 06/13] iio: health: max30102: Add check for part ID
  2017-11-19 20:38   ` Matt Ranostay
@ 2017-11-25 14:11     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:11 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:38:50 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>  
> 
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
> 
Applied.
> > ---
> >  drivers/iio/health/max30102.c | 18 ++++++++++++++++++
> >  1 file changed, 18 insertions(+)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 389a483..c43957e 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -32,6 +32,7 @@
> >
> >  #define MAX30102_REGMAP_NAME   "max30102_regmap"
> >  #define MAX30102_DRV_NAME      "max30102"
> > +#define MAX30102_PART_NUMBER   0x15
> >
> >  #define MAX30102_REG_INT_STATUS                        0x00
> >  #define MAX30102_REG_INT_STATUS_PWR_RDY                BIT(0)
> > @@ -83,6 +84,9 @@
> >  #define MAX30102_REG_TEMP_INTEGER              0x1f
> >  #define MAX30102_REG_TEMP_FRACTION             0x20
> >
> > +#define MAX30102_REG_REV_ID                    0xfe
> > +#define MAX30102_REG_PART_ID                   0xff
> > +
> >  struct max30102_data {
> >         struct i2c_client *client;
> >         struct iio_dev *indio_dev;
> > @@ -391,6 +395,7 @@ static int max30102_probe(struct i2c_client *client,
> >         struct iio_buffer *buffer;
> >         struct iio_dev *indio_dev;
> >         int ret;
> > +       unsigned int reg;
> >
> >         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> >         if (!indio_dev)
> > @@ -424,6 +429,19 @@ static int max30102_probe(struct i2c_client *client,
> >                 return PTR_ERR(data->regmap);
> >         }
> >
> > +       /* check part ID */
> > +       ret = regmap_read(data->regmap, MAX30102_REG_PART_ID, &reg);
> > +       if (ret)
> > +               return ret;
> > +       if (reg != MAX30102_PART_NUMBER)
> > +               return -ENODEV;
> > +
> > +       /* show revision ID */
> > +       ret = regmap_read(data->regmap, MAX30102_REG_REV_ID, &reg);
> > +       if (ret)
> > +               return ret;
> > +       dev_dbg(&client->dev, "max3010x revision %02x\n", reg);
> > +
> >         ret = max30102_set_powermode(data, false);
> >         if (ret)
> >                 return ret;
> > --
> > 2.7.4
> >  


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 07/13] iio: health: max30102: Introduce intensity channel macro
  2017-11-19 20:37   ` Matt Ranostay
@ 2017-11-25 14:12     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:12 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:37:00 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Signed-off-by: Peter Meerwald-Stalder <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>  
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
Applied.
> 
> > ---
> >  drivers/iio/health/max30102.c | 44 ++++++++++++++++---------------------------
> >  1 file changed, 16 insertions(+), 28 deletions(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index c43957e..968b54b 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -106,35 +106,23 @@ static const struct regmap_config max30102_regmap_config = {
> >
> >  static const unsigned long max30102_scan_masks[] = {0x3, 0};
> >
> > +#define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
> > +               .type = IIO_INTENSITY, \
> > +               .channel2 = _mod, \
> > +               .modified = 1, \
> > +               .scan_index = _si, \
> > +               .scan_type = { \
> > +                       .sign = 'u', \
> > +                       .shift = 8, \
> > +                       .realbits = 18, \
> > +                       .storagebits = 32, \
> > +                       .endianness = IIO_BE, \
> > +               }, \
> > +       }
> > +
> >  static const struct iio_chan_spec max30102_channels[] = {
> > -       {
> > -               .type = IIO_INTENSITY,
> > -               .channel2 = IIO_MOD_LIGHT_RED,
> > -               .modified = 1,
> > -
> > -               .scan_index = 0,
> > -               .scan_type = {
> > -                       .sign = 'u',
> > -                       .shift = 8,
> > -                       .realbits = 18,
> > -                       .storagebits = 32,
> > -                       .endianness = IIO_BE,
> > -               },
> > -       },
> > -       {
> > -               .type = IIO_INTENSITY,
> > -               .channel2 = IIO_MOD_LIGHT_IR,
> > -               .modified = 1,
> > -
> > -               .scan_index = 1,
> > -               .scan_type = {
> > -                       .sign = 'u',
> > -                       .shift = 8,
> > -                       .realbits = 18,
> > -                       .storagebits = 32,
> > -                       .endianness = IIO_BE,
> > -               },
> > -       },
> > +       MAX30102_INTENSITY_CHANNEL(0, IIO_MOD_LIGHT_RED),
> > +       MAX30102_INTENSITY_CHANNEL(1, IIO_MOD_LIGHT_IR),
> >         {
> >                 .type = IIO_TEMP,
> >                 .info_mask_separate =
> > --
> > 2.7.4
> >  


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 08/13] iio: health: max30102: Add power enable parameter to get_temp function
  2017-11-19 20:41   ` Matt Ranostay
@ 2017-11-25 14:15     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:15 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:41:37 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Chip must not be in shutdown for reading temperature, so briefly leave
> > shutdown if buffer is not already running
> >  
> 
> Looks good to me. I assume there is no setup delay required for power on though?
I assuming not but if there is then a follow up patch now...
> 
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>

Applied to togreg branch of iio.git.  A bit of fuzz given the other
temperature related patch that went via the fixes tree.

Jonathan


> 
> 
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> > ---
> >  drivers/iio/health/max30102.c | 36 +++++++++++++++++++++++-------------
> >  1 file changed, 23 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 968b54b..520d905 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -321,20 +321,31 @@ static int max30102_read_temp(struct max30102_data *data, int *val)
> >         return 0;
> >  }
> >
> > -static int max30102_get_temp(struct max30102_data *data, int *val)
> > +static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
> >  {
> >         int ret;
> >
> > +       if (en) {
> > +               ret = max30102_set_powermode(data, true);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> >         /* start acquisition */
> >         ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
> >                                  MAX30102_REG_TEMP_CONFIG_TEMP_EN,
> >                                  MAX30102_REG_TEMP_CONFIG_TEMP_EN);
> >         if (ret)
> > -               return ret;
> > +               goto out;
> >
> >         msleep(35);
> > +       ret = max30102_read_temp(data, val);
> > +
> > +out:
> > +       if (en)
> > +               max30102_set_powermode(data, false);
> >
> > -       return max30102_read_temp(data, val);
> > +       return ret;
> >  }
> >
> >  static int max30102_read_raw(struct iio_dev *indio_dev,
> > @@ -347,20 +358,19 @@ static int max30102_read_raw(struct iio_dev *indio_dev,
> >         switch (mask) {
> >         case IIO_CHAN_INFO_RAW:
> >                 /*
> > -                * Temperature reading can only be acquired while engine
> > -                * is running
> > +                * Temperature reading can only be acquired when not in
> > +                * shutdown; leave shutdown briefly when buffer not running
> >                  */
> >                 mutex_lock(&indio_dev->mlock);
> > -
> >                 if (!iio_buffer_enabled(indio_dev))
> > -                       ret = -EBUSY;
> > -               else {
> > -                       ret = max30102_get_temp(data, val);
> > -                       if (!ret)
> > -                               ret = IIO_VAL_INT;
> > -               }
> > -
> > +                       ret = max30102_get_temp(data, val, true);
> > +               else
> > +                       ret = max30102_get_temp(data, val, false);
> >                 mutex_unlock(&indio_dev->mlock);
> > +               if (ret)
> > +                       return ret;
> > +
> > +               ret = IIO_VAL_INT;
> >                 break;
> >         case IIO_CHAN_INFO_SCALE:
> >                 *val = 1000;  /* 62.5 */
> > --
> > 2.7.4
> >  


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 09/13] iio: health: max30102: Introduce indices for LED channels
  2017-11-19 20:42   ` Matt Ranostay
@ 2017-11-25 14:16     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:16 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:42:35 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>  
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
Applied.  Thanks,
> 
> > ---
> >  drivers/iio/health/max30102.c | 14 +++++++++++---
> >  1 file changed, 11 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 520d905..37176c2 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -34,6 +34,11 @@
> >  #define MAX30102_DRV_NAME      "max30102"
> >  #define MAX30102_PART_NUMBER   0x15
> >
> > +enum max3012_led_idx {
> > +       MAX30102_LED_RED,
> > +       MAX30102_LED_IR,
> > +};
> > +
> >  #define MAX30102_REG_INT_STATUS                        0x00
> >  #define MAX30102_REG_INT_STATUS_PWR_RDY                BIT(0)
> >  #define MAX30102_REG_INT_STATUS_PROX_INT       BIT(4)
> > @@ -104,7 +109,10 @@ static const struct regmap_config max30102_regmap_config = {
> >         .val_bits = 8,
> >  };
> >
> > -static const unsigned long max30102_scan_masks[] = {0x3, 0};
> > +static const unsigned long max30102_scan_masks[] = {
> > +       BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR),
> > +       0
> > +};
> >
> >  #define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
> >                 .type = IIO_INTENSITY, \
> > @@ -121,8 +129,8 @@ static const unsigned long max30102_scan_masks[] = {0x3, 0};
> >         }
> >
> >  static const struct iio_chan_spec max30102_channels[] = {
> > -       MAX30102_INTENSITY_CHANNEL(0, IIO_MOD_LIGHT_RED),
> > -       MAX30102_INTENSITY_CHANNEL(1, IIO_MOD_LIGHT_IR),
> > +       MAX30102_INTENSITY_CHANNEL(MAX30102_LED_RED, IIO_MOD_LIGHT_RED),
> > +       MAX30102_INTENSITY_CHANNEL(MAX30102_LED_IR, IIO_MOD_LIGHT_IR),
> >         {
> >                 .type = IIO_TEMP,
> >                 .info_mask_separate =
> > --
> > 2.7.4
> >  
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 10/13] iio: health: max30102: Move mode setting to buffer_postenable
  2017-11-19 20:56   ` Matt Ranostay
@ 2017-11-25 14:17     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:17 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:56:28 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Move the programming of the mode setting from init() to
> > buffer_postenable()
> >
> > Split out a separate function to
> > only update the power/shutdown bit
> >
> > This changes permits to more easily implement different
> > modes of measurements in further patches
> >
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>  
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
Applied.
> 
> > ---
> >  drivers/iio/health/max30102.c | 44 +++++++++++++++++++++++++++----------------
> >  1 file changed, 28 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 37176c2..1c7fe63 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -66,6 +66,7 @@ enum max3012_led_idx {
> >  #define MAX30102_REG_FIFO_CONFIG_AFULL         BIT(0)
> >
> >  #define MAX30102_REG_MODE_CONFIG               0x09
> > +#define MAX30102_REG_MODE_CONFIG_MODE_NONE     0x00
> >  #define MAX30102_REG_MODE_CONFIG_MODE_HR       0x02 /* red LED */
> >  #define MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2  0x03 /* red + IR LED */
> >  #define MAX30102_REG_MODE_CONFIG_MODE_MULTI    0x07 /* multi-LED mode */
> > @@ -139,25 +140,41 @@ static const struct iio_chan_spec max30102_channels[] = {
> >         },
> >  };
> >
> > -static int max30102_set_powermode(struct max30102_data *data, bool state)
> > +static int max30102_set_power(struct max30102_data *data, bool en)
> >  {
> >         return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
> >                                   MAX30102_REG_MODE_CONFIG_PWR,
> > -                                 state ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
> > +                                 en ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
> > +}
> > +
> > +static int max30102_set_powermode(struct max30102_data *data, u8 mode, bool en)
> > +{
> > +       u8 reg = mode;
> > +
> > +       if (!en)
> > +               reg |= MAX30102_REG_MODE_CONFIG_PWR;
> > +
> > +       return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
> > +                                 MAX30102_REG_MODE_CONFIG_PWR |
> > +                                 MAX30102_REG_MODE_CONFIG_MODE_MASK, reg);
> >  }
> >
> >  static int max30102_buffer_postenable(struct iio_dev *indio_dev)
> >  {
> >         struct max30102_data *data = iio_priv(indio_dev);
> > +       u8 reg;
> > +
> > +       reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
> >
> > -       return max30102_set_powermode(data, true);
> > +       return max30102_set_powermode(data, reg, true);
> >  }
> >
> >  static int max30102_buffer_predisable(struct iio_dev *indio_dev)
> >  {
> >         struct max30102_data *data = iio_priv(indio_dev);
> >
> > -       return max30102_set_powermode(data, false);
> > +       return max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
> > +                                     false);
> >  }
> >
> >  static const struct iio_buffer_setup_ops max30102_buffer_setup_ops = {
> > @@ -278,7 +295,7 @@ static int max30102_chip_init(struct max30102_data *data)
> >         if (ret)
> >                 return ret;
> >
> > -       /* enable 18-bit HR + SPO2 readings at 400Hz */
> > +       /* configure 18-bit HR + SpO2 readings at 400Hz */
> >         ret = regmap_write(data->regmap, MAX30102_REG_SPO2_CONFIG,
> >                                 (MAX30102_REG_SPO2_CONFIG_ADC_4096_STEPS
> >                                  << MAX30102_REG_SPO2_CONFIG_ADC_MASK_SHIFT) |
> > @@ -288,13 +305,6 @@ static int max30102_chip_init(struct max30102_data *data)
> >         if (ret)
> >                 return ret;
> >
> > -       /* enable HR + SPO2 mode */
> > -       ret = regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
> > -                                MAX30102_REG_MODE_CONFIG_MODE_MASK,
> > -                                MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2);
> > -       if (ret)
> > -               return ret;
> > -
> >         /* average 4 samples + generate FIFO interrupt */
> >         ret = regmap_write(data->regmap, MAX30102_REG_FIFO_CONFIG,
> >                                 (MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES
> > @@ -334,7 +344,7 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
> >         int ret;
> >
> >         if (en) {
> > -               ret = max30102_set_powermode(data, true);
> > +               ret = max30102_set_power(data, true);
> >                 if (ret)
> >                         return ret;
> >         }
> > @@ -351,7 +361,7 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
> >
> >  out:
> >         if (en)
> > -               max30102_set_powermode(data, false);
> > +               max30102_set_power(data, false);
> >
> >         return ret;
> >  }
> > @@ -448,7 +458,9 @@ static int max30102_probe(struct i2c_client *client,
> >                 return ret;
> >         dev_dbg(&client->dev, "max3010x revision %02x\n", reg);
> >
> > -       ret = max30102_set_powermode(data, false);
> > +       /* clear mode setting, chip shutdown */
> > +       ret = max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
> > +                                    false);
> >         if (ret)
> >                 return ret;
> >
> > @@ -479,7 +491,7 @@ static int max30102_remove(struct i2c_client *client)
> >         struct max30102_data *data = iio_priv(indio_dev);
> >
> >         iio_device_unregister(indio_dev);
> > -       max30102_set_powermode(data, false);
> > +       max30102_set_power(data, false);
> >
> >         return 0;
> >  }
> > --
> > 2.7.4
> >  


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 11/13] iio: health: max30102: Prepare for copying varying number of measurements
  2017-11-19 20:52   ` Matt Ranostay
@ 2017-11-25 14:18     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:18 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 12:52:56 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Current code assumes always 2 measurements (6 bytes) have to be copied,
> > prepare for more flexibility  
> 
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
Applied.
> 
> >
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> > ---
> >  drivers/iio/health/max30102.c | 15 ++++++++++-----
> >  1 file changed, 10 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 1c7fe63..86058f0 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -58,7 +58,7 @@ enum max3012_led_idx {
> >  #define MAX30102_REG_FIFO_OVR_CTR              0x05
> >  #define MAX30102_REG_FIFO_RD_PTR               0x06
> >  #define MAX30102_REG_FIFO_DATA                 0x07
> > -#define MAX30102_REG_FIFO_DATA_ENTRY_LEN       6
> > +#define MAX30102_REG_FIFO_DATA_BYTES           3
> >
> >  #define MAX30102_REG_FIFO_CONFIG               0x08
> >  #define MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES  BIT(1)
> > @@ -198,6 +198,11 @@ static inline int max30102_fifo_count(struct max30102_data *data)
> >         return 0;
> >  }
> >
> > +#define MAX30102_COPY_DATA(i) \
> > +       memcpy(&data->processed_buffer[(i)], \
> > +              &buffer[(i) * MAX30102_REG_FIFO_DATA_BYTES], \
> > +              MAX30102_REG_FIFO_DATA_BYTES)
> > +
> >  static int max30102_read_measurement(struct max30102_data *data)
> >  {
> >         int ret;
> > @@ -205,13 +210,13 @@ static int max30102_read_measurement(struct max30102_data *data)
> >
> >         ret = i2c_smbus_read_i2c_block_data(data->client,
> >                                             MAX30102_REG_FIFO_DATA,
> > -                                           MAX30102_REG_FIFO_DATA_ENTRY_LEN,
> > +                                           2 * MAX30102_REG_FIFO_DATA_BYTES,
> >                                             buffer);
> >
> > -       memcpy(&data->processed_buffer[0], &buffer[0], 3);
> > -       memcpy(&data->processed_buffer[1], &buffer[3], 3);
> > +       MAX30102_COPY_DATA(0);
> > +       MAX30102_COPY_DATA(1);
> >
> > -       return (ret == MAX30102_REG_FIFO_DATA_ENTRY_LEN) ? 0 : -EINVAL;
> > +       return (ret == 2 * MAX30102_REG_FIFO_DATA_BYTES) ? 0 : -EINVAL;
> >  }
> >
> >  static irqreturn_t max30102_interrupt_handler(int irq, void *private)
> > --
> > 2.7.4
> >  
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 12/13] iio: health: max30102: Add MAX30105 support
  2017-11-19 21:00   ` Matt Ranostay
@ 2017-11-25 14:19     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:19 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio

On Sun, 19 Nov 2017 13:00:51 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > The Maxim MAX30105 part adds a third LED (green) and uses a multi-LED
> > measuring mode producing three measurements
> >
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>  
> 
> Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
Applied.
> 
> > ---
> >  drivers/iio/health/max30102.c | 144 ++++++++++++++++++++++++++++++++++++++----
> >  1 file changed, 130 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
> > index 86058f0..15ccadc 100644
> > --- a/drivers/iio/health/max30102.c
> > +++ b/drivers/iio/health/max30102.c
> > @@ -3,6 +3,9 @@
> >   *
> >   * Copyright (C) 2017 Matt Ranostay <matt@ranostay.consulting>
> >   *
> > + * Support for MAX30105 optical particle sensor
> > + * Copyright (C) 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > + *
> >   * This program is free software; you can redistribute it and/or modify
> >   * it under the terms of the GNU General Public License as published by
> >   * the Free Software Foundation; either version 2 of the License, or
> > @@ -13,6 +16,7 @@
> >   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> >   * GNU General Public License for more details.
> >   *
> > + * 7-bit I2C chip address: 0x57
> >   * TODO: proximity power saving feature
> >   */
> >
> > @@ -34,9 +38,15 @@
> >  #define MAX30102_DRV_NAME      "max30102"
> >  #define MAX30102_PART_NUMBER   0x15
> >
> > +enum max30102_chip_id {
> > +       max30102,
> > +       max30105,
> > +};
> > +
> >  enum max3012_led_idx {
> >         MAX30102_LED_RED,
> >         MAX30102_LED_IR,
> > +       MAX30105_LED_GREEN,
> >  };
> >
> >  #define MAX30102_REG_INT_STATUS                        0x00
> > @@ -73,6 +83,11 @@ enum max3012_led_idx {
> >  #define MAX30102_REG_MODE_CONFIG_MODE_MASK     GENMASK(2, 0)
> >  #define MAX30102_REG_MODE_CONFIG_PWR           BIT(7)
> >
> > +#define MAX30102_REG_MODE_CONTROL_SLOT21       0x11 /* multi-LED control */
> > +#define MAX30102_REG_MODE_CONTROL_SLOT43       0x12
> > +#define MAX30102_REG_MODE_CONTROL_SLOT_MASK    (GENMASK(6, 4) | GENMASK(2, 0))
> > +#define MAX30102_REG_MODE_CONTROL_SLOT_SHIFT   4  
> 
> I assume slot is some time multiplexing of the LEDs?
> 
> > +
> >  #define MAX30102_REG_SPO2_CONFIG               0x0a
> >  #define MAX30102_REG_SPO2_CONFIG_PULSE_411_US  0x03
> >  #define MAX30102_REG_SPO2_CONFIG_SR_400HZ      0x03
> > @@ -83,6 +98,7 @@ enum max3012_led_idx {
> >
> >  #define MAX30102_REG_RED_LED_CONFIG            0x0c
> >  #define MAX30102_REG_IR_LED_CONFIG             0x0d
> > +#define MAX30105_REG_GREEN_LED_CONFIG          0x0e
> >
> >  #define MAX30102_REG_TEMP_CONFIG               0x21
> >  #define MAX30102_REG_TEMP_CONFIG_TEMP_EN       BIT(0)
> > @@ -98,9 +114,10 @@ struct max30102_data {
> >         struct iio_dev *indio_dev;
> >         struct mutex lock;
> >         struct regmap *regmap;
> > +       enum max30102_chip_id chip_id;
> >
> > -       u8 buffer[8];
> > -       __be32 processed_buffer[2]; /* 2 x 18-bit (padded to 32-bits) */
> > +       u8 buffer[12];
> > +       __be32 processed_buffer[3]; /* 3 x 18-bit (padded to 32-bits) */
> >  };
> >
> >  static const struct regmap_config max30102_regmap_config = {
> > @@ -115,6 +132,13 @@ static const unsigned long max30102_scan_masks[] = {
> >         0
> >  };
> >
> > +static const unsigned long max30105_scan_masks[] = {
> > +       BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR),
> > +       BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR) |
> > +               BIT(MAX30105_LED_GREEN),
> > +       0
> > +};
> > +
> >  #define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
> >                 .type = IIO_INTENSITY, \
> >                 .channel2 = _mod, \
> > @@ -140,6 +164,18 @@ static const struct iio_chan_spec max30102_channels[] = {
> >         },
> >  };
> >
> > +static const struct iio_chan_spec max30105_channels[] = {
> > +       MAX30102_INTENSITY_CHANNEL(MAX30102_LED_RED, IIO_MOD_LIGHT_RED),
> > +       MAX30102_INTENSITY_CHANNEL(MAX30102_LED_IR, IIO_MOD_LIGHT_IR),
> > +       MAX30102_INTENSITY_CHANNEL(MAX30105_LED_GREEN, IIO_MOD_LIGHT_GREEN),
> > +       {
> > +               .type = IIO_TEMP,
> > +               .info_mask_separate =
> > +                       BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
> > +               .scan_index = -1,
> > +       },
> > +};
> > +
> >  static int max30102_set_power(struct max30102_data *data, bool en)
> >  {
> >         return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
> > @@ -159,12 +195,40 @@ static int max30102_set_powermode(struct max30102_data *data, u8 mode, bool en)
> >                                   MAX30102_REG_MODE_CONFIG_MODE_MASK, reg);
> >  }
> >
> > +#define MAX30102_MODE_CONTROL_LED_SLOTS(slot2, slot1) \
> > +       ((slot2 << MAX30102_REG_MODE_CONTROL_SLOT_SHIFT) | slot1)
> > +
> >  static int max30102_buffer_postenable(struct iio_dev *indio_dev)
> >  {
> >         struct max30102_data *data = iio_priv(indio_dev);
> > +       int ret;
> >         u8 reg;
> >
> > -       reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
> > +       switch (*indio_dev->active_scan_mask) {
> > +       case BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR):
> > +               reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
> > +               break;
> > +       case BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR) |
> > +            BIT(MAX30105_LED_GREEN):
> > +               ret = regmap_update_bits(data->regmap,
> > +                                        MAX30102_REG_MODE_CONTROL_SLOT21,
> > +                                        MAX30102_REG_MODE_CONTROL_SLOT_MASK,
> > +                                        MAX30102_MODE_CONTROL_LED_SLOTS(2, 1));
> > +               if (ret)
> > +                       return ret;
> > +
> > +               ret = regmap_update_bits(data->regmap,
> > +                                        MAX30102_REG_MODE_CONTROL_SLOT43,
> > +                                        MAX30102_REG_MODE_CONTROL_SLOT_MASK,
> > +                                        MAX30102_MODE_CONTROL_LED_SLOTS(0, 3));
> > +               if (ret)
> > +                       return ret;
> > +
> > +               reg = MAX30102_REG_MODE_CONFIG_MODE_MULTI;
> > +               break;
> > +       default:
> > +               return -EINVAL;
> > +       }
> >
> >         return max30102_set_powermode(data, reg, true);
> >  }
> > @@ -203,32 +267,46 @@ static inline int max30102_fifo_count(struct max30102_data *data)
> >                &buffer[(i) * MAX30102_REG_FIFO_DATA_BYTES], \
> >                MAX30102_REG_FIFO_DATA_BYTES)
> >
> > -static int max30102_read_measurement(struct max30102_data *data)
> > +static int max30102_read_measurement(struct max30102_data *data,
> > +                                    unsigned int measurements)
> >  {
> >         int ret;
> >         u8 *buffer = (u8 *) &data->buffer;
> >
> >         ret = i2c_smbus_read_i2c_block_data(data->client,
> >                                             MAX30102_REG_FIFO_DATA,
> > -                                           2 * MAX30102_REG_FIFO_DATA_BYTES,
> > +                                           measurements *
> > +                                           MAX30102_REG_FIFO_DATA_BYTES,
> >                                             buffer);
> >
> > -       MAX30102_COPY_DATA(0);
> > -       MAX30102_COPY_DATA(1);
> > +       switch (measurements) {
> > +       case 3:
> > +               MAX30102_COPY_DATA(2);
> > +       case 2: /* fall-through */
> > +               MAX30102_COPY_DATA(1);
> > +       case 1: /* fall-through */
> > +               MAX30102_COPY_DATA(0);
> > +               break;
> > +       default:
> > +               return -EINVAL;
> > +       }
> >
> > -       return (ret == 2 * MAX30102_REG_FIFO_DATA_BYTES) ? 0 : -EINVAL;
> > +       return (ret == measurements * MAX30102_REG_FIFO_DATA_BYTES) ?
> > +              0 : -EINVAL;
> >  }
> >
> >  static irqreturn_t max30102_interrupt_handler(int irq, void *private)
> >  {
> >         struct iio_dev *indio_dev = private;
> >         struct max30102_data *data = iio_priv(indio_dev);
> > +       unsigned int measurements = bitmap_weight(indio_dev->active_scan_mask,
> > +                                                 indio_dev->masklength);
> >         int ret, cnt = 0;
> >
> >         mutex_lock(&data->lock);
> >
> >         while (cnt || (cnt = max30102_fifo_count(data)) > 0) {
> > -               ret = max30102_read_measurement(data);
> > +               ret = max30102_read_measurement(data, measurements);
> >                 if (ret)
> >                         break;
> >
> > @@ -274,6 +352,29 @@ static int max30102_led_init(struct max30102_data *data)
> >         if (ret)
> >                 return ret;
> >
> > +       if (data->chip_id == max30105) {
> > +               ret = of_property_read_u32(np,
> > +                       "maxim,green-led-current-microamp", &val);
> > +               if (ret) {
> > +                       dev_info(dev, "no green-led-current-microamp set\n");
> > +
> > +                       /* Default to 7 mA green LED */
> > +                       val = 7000;
> > +               }
> > +
> > +               ret = max30102_get_current_idx(val, &reg);
> > +               if (ret) {
> > +                       dev_err(dev, "invalid green LED current setting %d\n",
> > +                               val);
> > +                       return ret;
> > +               }
> > +
> > +               ret = regmap_write(data->regmap, MAX30105_REG_GREEN_LED_CONFIG,
> > +                                  reg);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> >         ret = of_property_read_u32(np, "maxim,ir-led-current-microamp", &val);
> >         if (ret) {
> >                 dev_info(dev, "no ir-led-current-microamp set\n");
> > @@ -429,10 +530,7 @@ static int max30102_probe(struct i2c_client *client,
> >         iio_device_attach_buffer(indio_dev, buffer);
> >
> >         indio_dev->name = MAX30102_DRV_NAME;
> > -       indio_dev->channels = max30102_channels;
> >         indio_dev->info = &max30102_info;
> > -       indio_dev->num_channels = ARRAY_SIZE(max30102_channels);
> > -       indio_dev->available_scan_masks = max30102_scan_masks;
> >         indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
> >         indio_dev->setup_ops = &max30102_buffer_setup_ops;
> >         indio_dev->dev.parent = &client->dev;
> > @@ -440,10 +538,26 @@ static int max30102_probe(struct i2c_client *client,
> >         data = iio_priv(indio_dev);
> >         data->indio_dev = indio_dev;
> >         data->client = client;
> > +       data->chip_id = id->driver_data;
> >
> >         mutex_init(&data->lock);
> >         i2c_set_clientdata(client, indio_dev);
> >
> > +       switch (data->chip_id) {
> > +       case max30105:
> > +               indio_dev->channels = max30105_channels;
> > +               indio_dev->num_channels = ARRAY_SIZE(max30105_channels);
> > +               indio_dev->available_scan_masks = max30105_scan_masks;
> > +               break;
> > +       case max30102:
> > +               indio_dev->channels = max30102_channels;
> > +               indio_dev->num_channels = ARRAY_SIZE(max30102_channels);
> > +               indio_dev->available_scan_masks = max30102_scan_masks;
> > +               break;
> > +       default:
> > +               return -ENODEV;
> > +       }
> > +
> >         data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config);
> >         if (IS_ERR(data->regmap)) {
> >                 dev_err(&client->dev, "regmap initialization failed\n");
> > @@ -502,13 +616,15 @@ static int max30102_remove(struct i2c_client *client)
> >  }
> >
> >  static const struct i2c_device_id max30102_id[] = {
> > -       { "max30102", 0 },
> > +       { "max30102", max30102 },
> > +       { "max30105", max30105 },
> >         {}
> >  };
> >  MODULE_DEVICE_TABLE(i2c, max30102_id);
> >
> >  static const struct of_device_id max30102_dt_ids[] = {
> >         { .compatible = "maxim,max30102" },
> > +       { .compatible = "maxim,max30105" },
> >         { }
> >  };
> >  MODULE_DEVICE_TABLE(of, max30102_dt_ids);
> > @@ -525,5 +641,5 @@ static struct i2c_driver max30102_driver = {
> >  module_i2c_driver(max30102_driver);
> >
> >  MODULE_AUTHOR("Matt Ranostay <matt@ranostay.consulting>");
> > -MODULE_DESCRIPTION("MAX30102 heart rate and pulse oximeter sensor");
> > +MODULE_DESCRIPTION("MAX30102 heart rate/pulse oximeter and MAX30105 particle sensor driver");
> >  MODULE_LICENSE("GPL");
> > --
> > 2.7.4
> >  


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 13/13] dt-bindings: iio: health: Add MAX30105 support to max30102.txt
  2017-11-19 20:35   ` Matt Ranostay
@ 2017-11-25 14:20     ` Jonathan Cameron
  0 siblings, 0 replies; 41+ messages in thread
From: Jonathan Cameron @ 2017-11-25 14:20 UTC (permalink / raw)
  To: Matt Ranostay; +Cc: Peter Meerwald-Stadler, linux-iio, Rob Herring

On Sun, 19 Nov 2017 12:35:04 -0800
Matt Ranostay <matt.ranostay@konsulko.com> wrote:

> On Fri, Oct 27, 2017 at 12:45 PM, Peter Meerwald-Stadler
> <pmeerw@pmeerw.net> wrote:
> > Signed-off-by: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
> > Cc: Matt Ranostay <matt.ranostay@konsulko.com>
> > Cc: Rob Herring <robh+dt@kernel.org>  
> 
> Reviewed-by: Matt Ranostay <matt.ranostay@konsulko.com>
>
Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to play with it.

Thanks,

Jonathan 
> > ---
> >  Documentation/devicetree/bindings/iio/health/max30102.txt | 8 ++++++--
> >  1 file changed, 6 insertions(+), 2 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/iio/health/max30102.txt b/Documentation/devicetree/bindings/iio/health/max30102.txt
> > index 8629c18..ef2ca0a 100644
> > --- a/Documentation/devicetree/bindings/iio/health/max30102.txt
> > +++ b/Documentation/devicetree/bindings/iio/health/max30102.txt
> > @@ -1,9 +1,11 @@
> >  Maxim MAX30102 heart rate and pulse oximeter sensor
> > +Maxim MAX30105 optical particle-sensing module
> >
> >  * https://datasheets.maximintegrated.com/en/ds/MAX30102.pdf
> > +* https://datasheets.maximintegrated.com/en/ds/MAX30105.pdf
> >
> >  Required properties:
> > -  - compatible: must be "maxim,max30102"
> > +  - compatible: must be "maxim,max30102" or "maxim,max30105"
> >    - reg: the I2C address of the sensor
> >    - interrupt-parent: should be the phandle for the interrupt controller
> >    - interrupts: the sole interrupt generated by the device
> > @@ -12,8 +14,10 @@ Required properties:
> >    interrupt client node bindings.
> >
> >  Optional properties:
> > -  - maxim,red-led-current-microamp: configuration for RED LED current
> > +  - maxim,red-led-current-microamp: configuration for red LED current
> >    - maxim,ir-led-current-microamp: configuration for IR LED current
> > +  - maxim,green-led-current-microamp: configuration for green LED current
> > +    (max30105 only)
> >
> >      Note that each step is approximately 200 microamps, ranging from 0 uA to
> >      50800 uA.
> > --
> > 2.7.4
> >  
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2017-11-25 14:21 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-10-27 19:45 [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Peter Meerwald-Stadler
2017-10-27 19:45 ` [PATCH v2 01/13] iio: health: max30102: Temperature should be in milli Celsius Peter Meerwald-Stadler
2017-11-19 21:09   ` Matt Ranostay
2017-11-25 14:04     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 02/13] iio: health: max30102: Fix missing newline in dev_err Peter Meerwald-Stadler
2017-11-19 20:28   ` Matt Ranostay
2017-11-25 14:05     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 03/13] iio: health: max30102: Remove inconsistent full stop in error message Peter Meerwald-Stadler
2017-11-19 20:28   ` Matt Ranostay
2017-11-25 14:06     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 04/13] iio: health: max30102: Fix mode config values Peter Meerwald-Stadler
2017-11-19 20:46   ` Matt Ranostay
2017-11-25 14:07     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 05/13] iio: health: max30102: Check retval of powermode function Peter Meerwald-Stadler
2017-11-19 20:43   ` Matt Ranostay
2017-11-25 14:08     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 06/13] iio: health: max30102: Add check for part ID Peter Meerwald-Stadler
2017-11-19 20:38   ` Matt Ranostay
2017-11-25 14:11     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 07/13] iio: health: max30102: Introduce intensity channel macro Peter Meerwald-Stadler
2017-11-19 20:37   ` Matt Ranostay
2017-11-25 14:12     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 08/13] iio: health: max30102: Add power enable parameter to get_temp function Peter Meerwald-Stadler
2017-11-19 20:41   ` Matt Ranostay
2017-11-25 14:15     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 09/13] iio: health: max30102: Introduce indices for LED channels Peter Meerwald-Stadler
2017-11-19 20:42   ` Matt Ranostay
2017-11-25 14:16     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 10/13] iio: health: max30102: Move mode setting to buffer_postenable Peter Meerwald-Stadler
2017-11-19 20:56   ` Matt Ranostay
2017-11-25 14:17     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 11/13] iio: health: max30102: Prepare for copying varying number of measurements Peter Meerwald-Stadler
2017-11-19 20:52   ` Matt Ranostay
2017-11-25 14:18     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 12/13] iio: health: max30102: Add MAX30105 support Peter Meerwald-Stadler
2017-11-19 21:00   ` Matt Ranostay
2017-11-25 14:19     ` Jonathan Cameron
2017-10-27 19:45 ` [PATCH v2 13/13] dt-bindings: iio: health: Add MAX30105 support to max30102.txt Peter Meerwald-Stadler
2017-11-19 20:35   ` Matt Ranostay
2017-11-25 14:20     ` Jonathan Cameron
2017-11-02 14:44 ` [PATCH v2 00/13] iio: health: Add MAX30105 support to max30102 driver Jonathan Cameron

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.