linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] atlas-ph-sensor: add conductivity sensor support
@ 2016-05-25  4:29 Matt Ranostay
  2016-05-25  4:29 ` [PATCH v3 1/3] iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips Matt Ranostay
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Matt Ranostay @ 2016-05-25  4:29 UTC (permalink / raw)
  To: linux-iio; +Cc: jic23, Matt Ranostay

Changes from v1:
 * Add IIO_ELECTRICALCONDUCTIVITY type rather than do doing weird conversion to ppm
 * move device tree mapping table above probe for of_match_device

Changes from v2:
 * IIO_ELECTRICALCONDUCTIVITY defined as siemens per meter
 * Add IIO_CHAN_INFO_SCALE for IIO_ELECTRICALCONDUCTIVITY channel

Matt Ranostay (3):
  iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips
  iio: electricalconductivity: add IIO_ELECTRICALCONDUCTIVITY type
  iio: chemical: atlas-ph-sensor: add EC feature

 Documentation/ABI/testing/sysfs-bus-iio            |   7 +
 .../bindings/iio/chemical/atlas,ec-sm.txt          |  22 ++
 drivers/iio/chemical/Kconfig                       |   8 +-
 drivers/iio/chemical/atlas-ph-sensor.c             | 267 ++++++++++++++++-----
 drivers/iio/industrialio-core.c                    |   1 +
 include/uapi/linux/iio/types.h                     |   1 +
 6 files changed, 246 insertions(+), 60 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt

-- 
2.7.4


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

* [PATCH v3 1/3] iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips
  2016-05-25  4:29 [PATCH v3 0/3] atlas-ph-sensor: add conductivity sensor support Matt Ranostay
@ 2016-05-25  4:29 ` Matt Ranostay
  2016-05-29 19:03   ` Jonathan Cameron
  2016-05-25  4:29 ` [PATCH v3 2/3] iio: electricalconductivity: add IIO_ELECTRICALCONDUCTIVITY type Matt Ranostay
  2016-05-25  4:29 ` [PATCH v3 3/3] iio: chemical: atlas-ph-sensor: add EC feature Matt Ranostay
  2 siblings, 1 reply; 7+ messages in thread
From: Matt Ranostay @ 2016-05-25  4:29 UTC (permalink / raw)
  To: linux-iio; +Cc: jic23, Matt Ranostay

Signed-off-by: Matt Ranostay <mranostay@gmail.com>
---
 drivers/iio/chemical/atlas-ph-sensor.c | 145 ++++++++++++++++++++-------------
 1 file changed, 90 insertions(+), 55 deletions(-)

diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c
index 62b37cd..e85477c 100644
--- a/drivers/iio/chemical/atlas-ph-sensor.c
+++ b/drivers/iio/chemical/atlas-ph-sensor.c
@@ -24,6 +24,7 @@
 #include <linux/irq_work.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
+#include <linux/of_device.h>
 #include <linux/regmap.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
@@ -43,20 +44,25 @@
 
 #define ATLAS_REG_PWR_CONTROL		0x06
 
-#define ATLAS_REG_CALIB_STATUS		0x0d
-#define ATLAS_REG_CALIB_STATUS_MASK	0x07
-#define ATLAS_REG_CALIB_STATUS_LOW	BIT(0)
-#define ATLAS_REG_CALIB_STATUS_MID	BIT(1)
-#define ATLAS_REG_CALIB_STATUS_HIGH	BIT(2)
+#define ATLAS_REG_PH_CALIB_STATUS	0x0d
+#define ATLAS_REG_PH_CALIB_STATUS_MASK	0x07
+#define ATLAS_REG_PH_CALIB_STATUS_LOW	BIT(0)
+#define ATLAS_REG_PH_CALIB_STATUS_MID	BIT(1)
+#define ATLAS_REG_PH_CALIB_STATUS_HIGH	BIT(2)
 
-#define ATLAS_REG_TEMP_DATA		0x0e
+#define ATLAS_REG_PH_TEMP_DATA		0x0e
 #define ATLAS_REG_PH_DATA		0x16
 
 #define ATLAS_PH_INT_TIME_IN_US		450000
 
+enum {
+	ATLAS_PH_SM,
+};
+
 struct atlas_data {
 	struct i2c_client *client;
 	struct iio_trigger *trig;
+	struct atlas_device *chip;
 	struct regmap *regmap;
 	struct irq_work work;
 
@@ -84,9 +90,10 @@ static const struct regmap_config atlas_regmap_config = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
-static const struct iio_chan_spec atlas_channels[] = {
+static const struct iio_chan_spec atlas_ph_channels[] = {
 	{
 		.type = IIO_PH,
+		.address = ATLAS_REG_PH_DATA,
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
 		.scan_index = 0,
@@ -100,7 +107,7 @@ static const struct iio_chan_spec atlas_channels[] = {
 	IIO_CHAN_SOFT_TIMESTAMP(1),
 	{
 		.type = IIO_TEMP,
-		.address = ATLAS_REG_TEMP_DATA,
+		.address = ATLAS_REG_PH_TEMP_DATA,
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
 		.output = 1,
@@ -108,6 +115,52 @@ static const struct iio_chan_spec atlas_channels[] = {
 	},
 };
 
+static int atlas_check_ph_calibration(struct atlas_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int ret;
+	unsigned int val;
+
+	ret = regmap_read(data->regmap, ATLAS_REG_PH_CALIB_STATUS, &val);
+	if (ret)
+		return ret;
+
+	if (!(val & ATLAS_REG_PH_CALIB_STATUS_MASK)) {
+		dev_warn(dev, "device has not been calibrated\n");
+		return 0;
+	}
+
+	if (!(val & ATLAS_REG_PH_CALIB_STATUS_LOW))
+		dev_warn(dev, "device missing low point calibration\n");
+
+	if (!(val & ATLAS_REG_PH_CALIB_STATUS_MID))
+		dev_warn(dev, "device missing mid point calibration\n");
+
+	if (!(val & ATLAS_REG_PH_CALIB_STATUS_HIGH))
+		dev_warn(dev, "device missing high point calibration\n");
+
+	return 0;
+}
+
+struct atlas_device {
+	const struct iio_chan_spec *channels;
+	int num_channels;
+	int data_reg;
+
+	int (*calibration)(struct atlas_data *data);
+	int delay;
+};
+
+static struct atlas_device atlas_devices[] = {
+	[ATLAS_PH_SM] = {
+				.channels = atlas_ph_channels,
+				.num_channels = 3,
+				.data_reg = ATLAS_REG_PH_DATA,
+				.calibration = &atlas_check_ph_calibration,
+				.delay = ATLAS_PH_INT_TIME_IN_US,
+	},
+};
+
 static int atlas_set_powermode(struct atlas_data *data, int on)
 {
 	return regmap_write(data->regmap, ATLAS_REG_PWR_CONTROL, on);
@@ -178,8 +231,9 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private)
 	struct atlas_data *data = iio_priv(indio_dev);
 	int ret;
 
-	ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA,
-			      (u8 *) &data->buffer, sizeof(data->buffer[0]));
+	ret = regmap_bulk_read(data->regmap, data->chip->data_reg,
+			      (u8 *) &data->buffer,
+			      sizeof(__be32) * (data->chip->num_channels - 2));
 
 	if (!ret)
 		iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
@@ -200,7 +254,7 @@ static irqreturn_t atlas_interrupt_handler(int irq, void *private)
 	return IRQ_HANDLED;
 }
 
-static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val)
+static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val)
 {
 	struct device *dev = &data->client->dev;
 	int suspended = pm_runtime_suspended(dev);
@@ -213,11 +267,9 @@ static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val)
 	}
 
 	if (suspended)
-		usleep_range(ATLAS_PH_INT_TIME_IN_US,
-			     ATLAS_PH_INT_TIME_IN_US + 100000);
+		usleep_range(data->chip->delay, data->chip->delay + 100000);
 
-	ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA,
-			      (u8 *) val, sizeof(*val));
+	ret = regmap_bulk_read(data->regmap, reg, (u8 *) val, sizeof(*val));
 
 	pm_runtime_mark_last_busy(dev);
 	pm_runtime_put_autosuspend(dev);
@@ -247,7 +299,8 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
 			if (iio_buffer_enabled(indio_dev))
 				ret = -EBUSY;
 			else
-				ret = atlas_read_ph_measurement(data, &reg);
+				ret = atlas_read_measurement(data,
+							chan->address, &reg);
 
 			mutex_unlock(&indio_dev->mlock);
 			break;
@@ -303,37 +356,24 @@ static const struct iio_info atlas_info = {
 	.write_raw = atlas_write_raw,
 };
 
-static int atlas_check_calibration(struct atlas_data *data)
-{
-	struct device *dev = &data->client->dev;
-	int ret;
-	unsigned int val;
-
-	ret = regmap_read(data->regmap, ATLAS_REG_CALIB_STATUS, &val);
-	if (ret)
-		return ret;
-
-	if (!(val & ATLAS_REG_CALIB_STATUS_MASK)) {
-		dev_warn(dev, "device has not been calibrated\n");
-		return 0;
-	}
-
-	if (!(val & ATLAS_REG_CALIB_STATUS_LOW))
-		dev_warn(dev, "device missing low point calibration\n");
-
-	if (!(val & ATLAS_REG_CALIB_STATUS_MID))
-		dev_warn(dev, "device missing mid point calibration\n");
-
-	if (!(val & ATLAS_REG_CALIB_STATUS_HIGH))
-		dev_warn(dev, "device missing high point calibration\n");
+static const struct i2c_device_id atlas_id[] = {
+	{ "atlas-ph-sm", ATLAS_PH_SM},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, atlas_id);
 
-	return 0;
+static const struct of_device_id atlas_dt_ids[] = {
+	{ .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
+	{ }
 };
+MODULE_DEVICE_TABLE(of, atlas_dt_ids);
 
 static int atlas_probe(struct i2c_client *client,
 		       const struct i2c_device_id *id)
 {
 	struct atlas_data *data;
+	struct atlas_device *chip;
+	const struct of_device_id *of_id;
 	struct iio_trigger *trig;
 	struct iio_dev *indio_dev;
 	int ret;
@@ -342,10 +382,16 @@ static int atlas_probe(struct i2c_client *client,
 	if (!indio_dev)
 		return -ENOMEM;
 
+	of_id = of_match_device(atlas_dt_ids, &client->dev);
+	if (!of_id)
+		chip = &atlas_devices[id->driver_data];
+	else
+		chip = &atlas_devices[(unsigned long)of_id->data];
+
 	indio_dev->info = &atlas_info;
 	indio_dev->name = ATLAS_DRV_NAME;
-	indio_dev->channels = atlas_channels;
-	indio_dev->num_channels = ARRAY_SIZE(atlas_channels);
+	indio_dev->channels = chip->channels;
+	indio_dev->num_channels = chip->num_channels;
 	indio_dev->modes = INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE;
 	indio_dev->dev.parent = &client->dev;
 
@@ -358,6 +404,7 @@ static int atlas_probe(struct i2c_client *client,
 	data = iio_priv(indio_dev);
 	data->client = client;
 	data->trig = trig;
+	data->chip = chip;
 	trig->dev.parent = indio_dev->dev.parent;
 	trig->ops = &atlas_interrupt_trigger_ops;
 	iio_trigger_set_drvdata(trig, indio_dev);
@@ -379,7 +426,7 @@ static int atlas_probe(struct i2c_client *client,
 		return -EINVAL;
 	}
 
-	ret = atlas_check_calibration(data);
+	ret = chip->calibration(data);
 	if (ret)
 		return ret;
 
@@ -480,18 +527,6 @@ static const struct dev_pm_ops atlas_pm_ops = {
 			   atlas_runtime_resume, NULL)
 };
 
-static const struct i2c_device_id atlas_id[] = {
-	{ "atlas-ph-sm", 0 },
-	{}
-};
-MODULE_DEVICE_TABLE(i2c, atlas_id);
-
-static const struct of_device_id atlas_dt_ids[] = {
-	{ .compatible = "atlas,ph-sm" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, atlas_dt_ids);
-
 static struct i2c_driver atlas_driver = {
 	.driver = {
 		.name	= ATLAS_DRV_NAME,
-- 
2.7.4


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

* [PATCH v3 2/3] iio: electricalconductivity: add IIO_ELECTRICALCONDUCTIVITY type
  2016-05-25  4:29 [PATCH v3 0/3] atlas-ph-sensor: add conductivity sensor support Matt Ranostay
  2016-05-25  4:29 ` [PATCH v3 1/3] iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips Matt Ranostay
@ 2016-05-25  4:29 ` Matt Ranostay
  2016-05-29 19:04   ` Jonathan Cameron
  2016-05-25  4:29 ` [PATCH v3 3/3] iio: chemical: atlas-ph-sensor: add EC feature Matt Ranostay
  2 siblings, 1 reply; 7+ messages in thread
From: Matt Ranostay @ 2016-05-25  4:29 UTC (permalink / raw)
  To: linux-iio; +Cc: jic23, Matt Ranostay

Signed-off-by: Matt Ranostay <mranostay@gmail.com>
---
 Documentation/ABI/testing/sysfs-bus-iio | 7 +++++++
 drivers/iio/industrialio-core.c         | 1 +
 include/uapi/linux/iio/types.h          | 1 +
 3 files changed, 9 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index df44998..e7f590c 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -1565,3 +1565,10 @@ Description:
 		* X is in the plane of the propellers, perpendicular to Y axis,
 		  and positive towards the starboard side of the UAV ;
 		* Z is perpendicular to propellers plane and positive upwards.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_electricalconductivity_raw
+KernelVersion:	4.8
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled no offset etc.) electric conductivity reading that
+		can be processed to siemens per meter.
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index e6319a9..2a85bd8 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -80,6 +80,7 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_RESISTANCE] = "resistance",
 	[IIO_PH] = "ph",
 	[IIO_UVINDEX] = "uvindex",
+	[IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity",
 };
 
 static const char * const iio_modifier_names[] = {
diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h
index b0916fc..22e5e58 100644
--- a/include/uapi/linux/iio/types.h
+++ b/include/uapi/linux/iio/types.h
@@ -39,6 +39,7 @@ enum iio_chan_type {
 	IIO_RESISTANCE,
 	IIO_PH,
 	IIO_UVINDEX,
+	IIO_ELECTRICALCONDUCTIVITY,
 };
 
 enum iio_modifier {
-- 
2.7.4


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

* [PATCH v3 3/3] iio: chemical: atlas-ph-sensor: add EC feature
  2016-05-25  4:29 [PATCH v3 0/3] atlas-ph-sensor: add conductivity sensor support Matt Ranostay
  2016-05-25  4:29 ` [PATCH v3 1/3] iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips Matt Ranostay
  2016-05-25  4:29 ` [PATCH v3 2/3] iio: electricalconductivity: add IIO_ELECTRICALCONDUCTIVITY type Matt Ranostay
@ 2016-05-25  4:29 ` Matt Ranostay
  2016-05-29 19:05   ` Jonathan Cameron
  2 siblings, 1 reply; 7+ messages in thread
From: Matt Ranostay @ 2016-05-25  4:29 UTC (permalink / raw)
  To: linux-iio; +Cc: jic23, Matt Ranostay

Signed-off-by: Matt Ranostay <mranostay@gmail.com>
---
 .../bindings/iio/chemical/atlas,ec-sm.txt          |  22 ++++
 drivers/iio/chemical/Kconfig                       |   8 +-
 drivers/iio/chemical/atlas-ph-sensor.c             | 122 ++++++++++++++++++++-
 3 files changed, 147 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt

diff --git a/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt b/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt
new file mode 100644
index 0000000..2962bd9
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt
@@ -0,0 +1,22 @@
+* Atlas Scientific EC-SM OEM sensor
+
+http://www.atlas-scientific.com/_files/_datasheets/_oem/EC_oem_datasheet.pdf
+
+Required properties:
+
+  - compatible: must be "atlas,ec-sm"
+  - 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
+
+  Refer to interrupt-controller/interrupts.txt for generic interrupt client
+  node bindings.
+
+Example:
+
+atlas@64 {
+	compatible = "atlas,ec-sm";
+	reg = <0x64>;
+	interrupt-parent = <&gpio1>;
+	interrupts = <16 2>;
+};
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index f73290f..4bcc025 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -5,15 +5,17 @@
 menu "Chemical Sensors"
 
 config ATLAS_PH_SENSOR
-	tristate "Atlas Scientific OEM pH-SM sensor"
+	tristate "Atlas Scientific OEM SM sensors"
 	depends on I2C
 	select REGMAP_I2C
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	select IRQ_WORK
 	help
-	 Say Y here to build I2C interface support for the Atlas
-	 Scientific OEM pH-SM sensor.
+	 Say Y here to build I2C interface support for the following
+	 Atlas Scientific OEM SM sensors:
+	    * pH SM sensor
+	    * EC SM sensor
 
 	 To compile this driver as module, choose M here: the
 	 module will be called atlas-ph-sensor.
diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c
index e85477c..02e85db 100644
--- a/drivers/iio/chemical/atlas-ph-sensor.c
+++ b/drivers/iio/chemical/atlas-ph-sensor.c
@@ -50,13 +50,28 @@
 #define ATLAS_REG_PH_CALIB_STATUS_MID	BIT(1)
 #define ATLAS_REG_PH_CALIB_STATUS_HIGH	BIT(2)
 
+#define ATLAS_REG_EC_CALIB_STATUS		0x0f
+#define ATLAS_REG_EC_CALIB_STATUS_MASK		0x0f
+#define ATLAS_REG_EC_CALIB_STATUS_DRY		BIT(0)
+#define ATLAS_REG_EC_CALIB_STATUS_SINGLE	BIT(1)
+#define ATLAS_REG_EC_CALIB_STATUS_LOW		BIT(2)
+#define ATLAS_REG_EC_CALIB_STATUS_HIGH		BIT(3)
+
 #define ATLAS_REG_PH_TEMP_DATA		0x0e
 #define ATLAS_REG_PH_DATA		0x16
 
+#define ATLAS_REG_EC_PROBE		0x08
+#define ATLAS_REG_EC_TEMP_DATA		0x10
+#define ATLAS_REG_EC_DATA		0x18
+#define ATLAS_REG_TDS_DATA		0x1c
+#define ATLAS_REG_PSS_DATA		0x20
+
 #define ATLAS_PH_INT_TIME_IN_US		450000
+#define ATLAS_EC_INT_TIME_IN_US		650000
 
 enum {
 	ATLAS_PH_SM,
+	ATLAS_EC_SM,
 };
 
 struct atlas_data {
@@ -66,12 +81,13 @@ struct atlas_data {
 	struct regmap *regmap;
 	struct irq_work work;
 
-	__be32 buffer[4]; /* 32-bit pH data + 32-bit pad + 64-bit timestamp */
+	__be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */
 };
 
 static const struct regmap_range atlas_volatile_ranges[] = {
 	regmap_reg_range(ATLAS_REG_INT_CONTROL, ATLAS_REG_INT_CONTROL),
 	regmap_reg_range(ATLAS_REG_PH_DATA, ATLAS_REG_PH_DATA + 4),
+	regmap_reg_range(ATLAS_REG_EC_DATA, ATLAS_REG_PSS_DATA + 4),
 };
 
 static const struct regmap_access_table atlas_volatile_table = {
@@ -86,7 +102,7 @@ static const struct regmap_config atlas_regmap_config = {
 	.val_bits = 8,
 
 	.volatile_table = &atlas_volatile_table,
-	.max_register = ATLAS_REG_PH_DATA + 4,
+	.max_register = ATLAS_REG_PSS_DATA + 4,
 	.cache_type = REGCACHE_RBTREE,
 };
 
@@ -115,6 +131,50 @@ static const struct iio_chan_spec atlas_ph_channels[] = {
 	},
 };
 
+#define ATLAS_EC_CHANNEL(_idx, _addr) \
+	{\
+		.type = IIO_CONCENTRATION, \
+		.indexed = 1, \
+		.channel = _idx, \
+		.address = _addr, \
+		.info_mask_separate = \
+			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
+		.scan_index = _idx + 1, \
+		.scan_type = { \
+			.sign = 'u', \
+			.realbits = 32, \
+			.storagebits = 32, \
+			.endianness = IIO_BE, \
+		}, \
+	}
+
+static const struct iio_chan_spec atlas_ec_channels[] = {
+	{
+		.type = IIO_ELECTRICALCONDUCTIVITY,
+		.address = ATLAS_REG_EC_DATA,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 32,
+			.storagebits = 32,
+			.endianness = IIO_BE,
+		},
+	},
+	ATLAS_EC_CHANNEL(0, ATLAS_REG_TDS_DATA),
+	ATLAS_EC_CHANNEL(1, ATLAS_REG_PSS_DATA),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+	{
+		.type = IIO_TEMP,
+		.address = ATLAS_REG_EC_TEMP_DATA,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+		.output = 1,
+		.scan_index = -1
+	},
+};
+
 static int atlas_check_ph_calibration(struct atlas_data *data)
 {
 	struct device *dev = &data->client->dev;
@@ -142,6 +202,44 @@ static int atlas_check_ph_calibration(struct atlas_data *data)
 	return 0;
 }
 
+static int atlas_check_ec_calibration(struct atlas_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int ret;
+	unsigned int val;
+
+	ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &val, 2);
+	if (ret)
+		return ret;
+
+	dev_info(dev, "probe set to K = %d.%.2d", be16_to_cpu(val) / 100,
+						 be16_to_cpu(val) % 100);
+
+	ret = regmap_read(data->regmap, ATLAS_REG_EC_CALIB_STATUS, &val);
+	if (ret)
+		return ret;
+
+	if (!(val & ATLAS_REG_EC_CALIB_STATUS_MASK)) {
+		dev_warn(dev, "device has not been calibrated\n");
+		return 0;
+	}
+
+	if (!(val & ATLAS_REG_EC_CALIB_STATUS_DRY))
+		dev_warn(dev, "device missing dry point calibration\n");
+
+	if (val & ATLAS_REG_EC_CALIB_STATUS_SINGLE) {
+		dev_warn(dev, "device using single point calibration\n");
+	} else {
+		if (!(val & ATLAS_REG_EC_CALIB_STATUS_LOW))
+			dev_warn(dev, "device missing low point calibration\n");
+
+		if (!(val & ATLAS_REG_EC_CALIB_STATUS_HIGH))
+			dev_warn(dev, "device missing high point calibration\n");
+	}
+
+	return 0;
+}
+
 struct atlas_device {
 	const struct iio_chan_spec *channels;
 	int num_channels;
@@ -159,6 +257,14 @@ static struct atlas_device atlas_devices[] = {
 				.calibration = &atlas_check_ph_calibration,
 				.delay = ATLAS_PH_INT_TIME_IN_US,
 	},
+	[ATLAS_EC_SM] = {
+				.channels = atlas_ec_channels,
+				.num_channels = 5,
+				.data_reg = ATLAS_REG_EC_DATA,
+				.calibration = &atlas_check_ec_calibration,
+				.delay = ATLAS_EC_INT_TIME_IN_US,
+	},
+
 };
 
 static int atlas_set_powermode(struct atlas_data *data, int on)
@@ -294,6 +400,8 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
 					      (u8 *) &reg, sizeof(reg));
 			break;
 		case IIO_PH:
+		case IIO_CONCENTRATION:
+		case IIO_ELECTRICALCONDUCTIVITY:
 			mutex_lock(&indio_dev->mlock);
 
 			if (iio_buffer_enabled(indio_dev))
@@ -324,6 +432,14 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
 			*val = 1; /* 0.001 */
 			*val2 = 1000;
 			break;
+		case IIO_ELECTRICALCONDUCTIVITY:
+			*val = 1; /* 0.00001 */
+			*val = 100000;
+			break;
+		case IIO_CONCENTRATION:
+			*val = 0; /* 0.000000001 */
+			*val2 = 1000;
+			return IIO_VAL_INT_PLUS_NANO;
 		default:
 			return -EINVAL;
 		}
@@ -358,12 +474,14 @@ static const struct iio_info atlas_info = {
 
 static const struct i2c_device_id atlas_id[] = {
 	{ "atlas-ph-sm", ATLAS_PH_SM},
+	{ "atlas-ec-sm", ATLAS_EC_SM},
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, atlas_id);
 
 static const struct of_device_id atlas_dt_ids[] = {
 	{ .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
+	{ .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, atlas_dt_ids);
-- 
2.7.4


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

* Re: [PATCH v3 1/3] iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips
  2016-05-25  4:29 ` [PATCH v3 1/3] iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips Matt Ranostay
@ 2016-05-29 19:03   ` Jonathan Cameron
  0 siblings, 0 replies; 7+ messages in thread
From: Jonathan Cameron @ 2016-05-29 19:03 UTC (permalink / raw)
  To: Matt Ranostay, linux-iio

On 25/05/16 05:29, Matt Ranostay wrote:
> Signed-off-by: Matt Ranostay <mranostay@gmail.com>
> ---
Applied to the togreg branch of iio.git - initially pushed out as testing for
the autobuilders to play with it.

Thanks,

Jonathan
>  drivers/iio/chemical/atlas-ph-sensor.c | 145 ++++++++++++++++++++-------------
>  1 file changed, 90 insertions(+), 55 deletions(-)
> 
> diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c
> index 62b37cd..e85477c 100644
> --- a/drivers/iio/chemical/atlas-ph-sensor.c
> +++ b/drivers/iio/chemical/atlas-ph-sensor.c
> @@ -24,6 +24,7 @@
>  #include <linux/irq_work.h>
>  #include <linux/gpio.h>
>  #include <linux/i2c.h>
> +#include <linux/of_device.h>
>  #include <linux/regmap.h>
>  #include <linux/iio/iio.h>
>  #include <linux/iio/buffer.h>
> @@ -43,20 +44,25 @@
>  
>  #define ATLAS_REG_PWR_CONTROL		0x06
>  
> -#define ATLAS_REG_CALIB_STATUS		0x0d
> -#define ATLAS_REG_CALIB_STATUS_MASK	0x07
> -#define ATLAS_REG_CALIB_STATUS_LOW	BIT(0)
> -#define ATLAS_REG_CALIB_STATUS_MID	BIT(1)
> -#define ATLAS_REG_CALIB_STATUS_HIGH	BIT(2)
> +#define ATLAS_REG_PH_CALIB_STATUS	0x0d
> +#define ATLAS_REG_PH_CALIB_STATUS_MASK	0x07
> +#define ATLAS_REG_PH_CALIB_STATUS_LOW	BIT(0)
> +#define ATLAS_REG_PH_CALIB_STATUS_MID	BIT(1)
> +#define ATLAS_REG_PH_CALIB_STATUS_HIGH	BIT(2)
>  
> -#define ATLAS_REG_TEMP_DATA		0x0e
> +#define ATLAS_REG_PH_TEMP_DATA		0x0e
>  #define ATLAS_REG_PH_DATA		0x16
>  
>  #define ATLAS_PH_INT_TIME_IN_US		450000
>  
> +enum {
> +	ATLAS_PH_SM,
> +};
> +
>  struct atlas_data {
>  	struct i2c_client *client;
>  	struct iio_trigger *trig;
> +	struct atlas_device *chip;
>  	struct regmap *regmap;
>  	struct irq_work work;
>  
> @@ -84,9 +90,10 @@ static const struct regmap_config atlas_regmap_config = {
>  	.cache_type = REGCACHE_RBTREE,
>  };
>  
> -static const struct iio_chan_spec atlas_channels[] = {
> +static const struct iio_chan_spec atlas_ph_channels[] = {
>  	{
>  		.type = IIO_PH,
> +		.address = ATLAS_REG_PH_DATA,
>  		.info_mask_separate =
>  			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
>  		.scan_index = 0,
> @@ -100,7 +107,7 @@ static const struct iio_chan_spec atlas_channels[] = {
>  	IIO_CHAN_SOFT_TIMESTAMP(1),
>  	{
>  		.type = IIO_TEMP,
> -		.address = ATLAS_REG_TEMP_DATA,
> +		.address = ATLAS_REG_PH_TEMP_DATA,
>  		.info_mask_separate =
>  			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
>  		.output = 1,
> @@ -108,6 +115,52 @@ static const struct iio_chan_spec atlas_channels[] = {
>  	},
>  };
>  
> +static int atlas_check_ph_calibration(struct atlas_data *data)
> +{
> +	struct device *dev = &data->client->dev;
> +	int ret;
> +	unsigned int val;
> +
> +	ret = regmap_read(data->regmap, ATLAS_REG_PH_CALIB_STATUS, &val);
> +	if (ret)
> +		return ret;
> +
> +	if (!(val & ATLAS_REG_PH_CALIB_STATUS_MASK)) {
> +		dev_warn(dev, "device has not been calibrated\n");
> +		return 0;
> +	}
> +
> +	if (!(val & ATLAS_REG_PH_CALIB_STATUS_LOW))
> +		dev_warn(dev, "device missing low point calibration\n");
> +
> +	if (!(val & ATLAS_REG_PH_CALIB_STATUS_MID))
> +		dev_warn(dev, "device missing mid point calibration\n");
> +
> +	if (!(val & ATLAS_REG_PH_CALIB_STATUS_HIGH))
> +		dev_warn(dev, "device missing high point calibration\n");
> +
> +	return 0;
> +}
> +
> +struct atlas_device {
> +	const struct iio_chan_spec *channels;
> +	int num_channels;
> +	int data_reg;
> +
> +	int (*calibration)(struct atlas_data *data);
> +	int delay;
> +};
> +
> +static struct atlas_device atlas_devices[] = {
> +	[ATLAS_PH_SM] = {
> +				.channels = atlas_ph_channels,
> +				.num_channels = 3,
> +				.data_reg = ATLAS_REG_PH_DATA,
> +				.calibration = &atlas_check_ph_calibration,
> +				.delay = ATLAS_PH_INT_TIME_IN_US,
> +	},
> +};
> +
>  static int atlas_set_powermode(struct atlas_data *data, int on)
>  {
>  	return regmap_write(data->regmap, ATLAS_REG_PWR_CONTROL, on);
> @@ -178,8 +231,9 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private)
>  	struct atlas_data *data = iio_priv(indio_dev);
>  	int ret;
>  
> -	ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA,
> -			      (u8 *) &data->buffer, sizeof(data->buffer[0]));
> +	ret = regmap_bulk_read(data->regmap, data->chip->data_reg,
> +			      (u8 *) &data->buffer,
> +			      sizeof(__be32) * (data->chip->num_channels - 2));
>  
>  	if (!ret)
>  		iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
> @@ -200,7 +254,7 @@ static irqreturn_t atlas_interrupt_handler(int irq, void *private)
>  	return IRQ_HANDLED;
>  }
>  
> -static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val)
> +static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val)
>  {
>  	struct device *dev = &data->client->dev;
>  	int suspended = pm_runtime_suspended(dev);
> @@ -213,11 +267,9 @@ static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val)
>  	}
>  
>  	if (suspended)
> -		usleep_range(ATLAS_PH_INT_TIME_IN_US,
> -			     ATLAS_PH_INT_TIME_IN_US + 100000);
> +		usleep_range(data->chip->delay, data->chip->delay + 100000);
>  
> -	ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA,
> -			      (u8 *) val, sizeof(*val));
> +	ret = regmap_bulk_read(data->regmap, reg, (u8 *) val, sizeof(*val));
>  
>  	pm_runtime_mark_last_busy(dev);
>  	pm_runtime_put_autosuspend(dev);
> @@ -247,7 +299,8 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
>  			if (iio_buffer_enabled(indio_dev))
>  				ret = -EBUSY;
>  			else
> -				ret = atlas_read_ph_measurement(data, &reg);
> +				ret = atlas_read_measurement(data,
> +							chan->address, &reg);
>  
>  			mutex_unlock(&indio_dev->mlock);
>  			break;
> @@ -303,37 +356,24 @@ static const struct iio_info atlas_info = {
>  	.write_raw = atlas_write_raw,
>  };
>  
> -static int atlas_check_calibration(struct atlas_data *data)
> -{
> -	struct device *dev = &data->client->dev;
> -	int ret;
> -	unsigned int val;
> -
> -	ret = regmap_read(data->regmap, ATLAS_REG_CALIB_STATUS, &val);
> -	if (ret)
> -		return ret;
> -
> -	if (!(val & ATLAS_REG_CALIB_STATUS_MASK)) {
> -		dev_warn(dev, "device has not been calibrated\n");
> -		return 0;
> -	}
> -
> -	if (!(val & ATLAS_REG_CALIB_STATUS_LOW))
> -		dev_warn(dev, "device missing low point calibration\n");
> -
> -	if (!(val & ATLAS_REG_CALIB_STATUS_MID))
> -		dev_warn(dev, "device missing mid point calibration\n");
> -
> -	if (!(val & ATLAS_REG_CALIB_STATUS_HIGH))
> -		dev_warn(dev, "device missing high point calibration\n");
> +static const struct i2c_device_id atlas_id[] = {
> +	{ "atlas-ph-sm", ATLAS_PH_SM},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(i2c, atlas_id);
>  
> -	return 0;
> +static const struct of_device_id atlas_dt_ids[] = {
> +	{ .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
> +	{ }
>  };
> +MODULE_DEVICE_TABLE(of, atlas_dt_ids);
>  
>  static int atlas_probe(struct i2c_client *client,
>  		       const struct i2c_device_id *id)
>  {
>  	struct atlas_data *data;
> +	struct atlas_device *chip;
> +	const struct of_device_id *of_id;
>  	struct iio_trigger *trig;
>  	struct iio_dev *indio_dev;
>  	int ret;
> @@ -342,10 +382,16 @@ static int atlas_probe(struct i2c_client *client,
>  	if (!indio_dev)
>  		return -ENOMEM;
>  
> +	of_id = of_match_device(atlas_dt_ids, &client->dev);
> +	if (!of_id)
> +		chip = &atlas_devices[id->driver_data];
> +	else
> +		chip = &atlas_devices[(unsigned long)of_id->data];
> +
>  	indio_dev->info = &atlas_info;
>  	indio_dev->name = ATLAS_DRV_NAME;
> -	indio_dev->channels = atlas_channels;
> -	indio_dev->num_channels = ARRAY_SIZE(atlas_channels);
> +	indio_dev->channels = chip->channels;
> +	indio_dev->num_channels = chip->num_channels;
>  	indio_dev->modes = INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE;
>  	indio_dev->dev.parent = &client->dev;
>  
> @@ -358,6 +404,7 @@ static int atlas_probe(struct i2c_client *client,
>  	data = iio_priv(indio_dev);
>  	data->client = client;
>  	data->trig = trig;
> +	data->chip = chip;
>  	trig->dev.parent = indio_dev->dev.parent;
>  	trig->ops = &atlas_interrupt_trigger_ops;
>  	iio_trigger_set_drvdata(trig, indio_dev);
> @@ -379,7 +426,7 @@ static int atlas_probe(struct i2c_client *client,
>  		return -EINVAL;
>  	}
>  
> -	ret = atlas_check_calibration(data);
> +	ret = chip->calibration(data);
>  	if (ret)
>  		return ret;
>  
> @@ -480,18 +527,6 @@ static const struct dev_pm_ops atlas_pm_ops = {
>  			   atlas_runtime_resume, NULL)
>  };
>  
> -static const struct i2c_device_id atlas_id[] = {
> -	{ "atlas-ph-sm", 0 },
> -	{}
> -};
> -MODULE_DEVICE_TABLE(i2c, atlas_id);
> -
> -static const struct of_device_id atlas_dt_ids[] = {
> -	{ .compatible = "atlas,ph-sm" },
> -	{ }
> -};
> -MODULE_DEVICE_TABLE(of, atlas_dt_ids);
> -
>  static struct i2c_driver atlas_driver = {
>  	.driver = {
>  		.name	= ATLAS_DRV_NAME,
> 


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

* Re: [PATCH v3 2/3] iio: electricalconductivity: add IIO_ELECTRICALCONDUCTIVITY type
  2016-05-25  4:29 ` [PATCH v3 2/3] iio: electricalconductivity: add IIO_ELECTRICALCONDUCTIVITY type Matt Ranostay
@ 2016-05-29 19:04   ` Jonathan Cameron
  0 siblings, 0 replies; 7+ messages in thread
From: Jonathan Cameron @ 2016-05-29 19:04 UTC (permalink / raw)
  To: Matt Ranostay, linux-iio

On 25/05/16 05:29, Matt Ranostay wrote:
> Signed-off-by: Matt Ranostay <mranostay@gmail.com>
Applied to the togreg branch of iio.git - initially pushed out as testing for
the autobuilders to ignore it.

Thanks,

Jonathan
> ---
>  Documentation/ABI/testing/sysfs-bus-iio | 7 +++++++
>  drivers/iio/industrialio-core.c         | 1 +
>  include/uapi/linux/iio/types.h          | 1 +
>  3 files changed, 9 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index df44998..e7f590c 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -1565,3 +1565,10 @@ Description:
>  		* X is in the plane of the propellers, perpendicular to Y axis,
>  		  and positive towards the starboard side of the UAV ;
>  		* Z is perpendicular to propellers plane and positive upwards.
> +
> +What:		/sys/bus/iio/devices/iio:deviceX/in_electricalconductivity_raw
> +KernelVersion:	4.8
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		Raw (unscaled no offset etc.) electric conductivity reading that
> +		can be processed to siemens per meter.
> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> index e6319a9..2a85bd8 100644
> --- a/drivers/iio/industrialio-core.c
> +++ b/drivers/iio/industrialio-core.c
> @@ -80,6 +80,7 @@ static const char * const iio_chan_type_name_spec[] = {
>  	[IIO_RESISTANCE] = "resistance",
>  	[IIO_PH] = "ph",
>  	[IIO_UVINDEX] = "uvindex",
> +	[IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity",
>  };
>  
>  static const char * const iio_modifier_names[] = {
> diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h
> index b0916fc..22e5e58 100644
> --- a/include/uapi/linux/iio/types.h
> +++ b/include/uapi/linux/iio/types.h
> @@ -39,6 +39,7 @@ enum iio_chan_type {
>  	IIO_RESISTANCE,
>  	IIO_PH,
>  	IIO_UVINDEX,
> +	IIO_ELECTRICALCONDUCTIVITY,
>  };
>  
>  enum iio_modifier {
> 


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

* Re: [PATCH v3 3/3] iio: chemical: atlas-ph-sensor: add EC feature
  2016-05-25  4:29 ` [PATCH v3 3/3] iio: chemical: atlas-ph-sensor: add EC feature Matt Ranostay
@ 2016-05-29 19:05   ` Jonathan Cameron
  0 siblings, 0 replies; 7+ messages in thread
From: Jonathan Cameron @ 2016-05-29 19:05 UTC (permalink / raw)
  To: Matt Ranostay, linux-iio

On 25/05/16 05:29, Matt Ranostay wrote:
> Signed-off-by: Matt Ranostay <mranostay@gmail.com>
Trivial binding so I doubt anyone cares - though technically it should have gone
to the devicetree list...

Applied to the togreg branch of iio.git - initially pushed out as testing.

Thanks,

Jonathan
> ---
>  .../bindings/iio/chemical/atlas,ec-sm.txt          |  22 ++++
>  drivers/iio/chemical/Kconfig                       |   8 +-
>  drivers/iio/chemical/atlas-ph-sensor.c             | 122 ++++++++++++++++++++-
>  3 files changed, 147 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt b/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt
> new file mode 100644
> index 0000000..2962bd9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt
> @@ -0,0 +1,22 @@
> +* Atlas Scientific EC-SM OEM sensor
> +
> +http://www.atlas-scientific.com/_files/_datasheets/_oem/EC_oem_datasheet.pdf
> +
> +Required properties:
> +
> +  - compatible: must be "atlas,ec-sm"
> +  - 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
> +
> +  Refer to interrupt-controller/interrupts.txt for generic interrupt client
> +  node bindings.
> +
> +Example:
> +
> +atlas@64 {
> +	compatible = "atlas,ec-sm";
> +	reg = <0x64>;
> +	interrupt-parent = <&gpio1>;
> +	interrupts = <16 2>;
> +};
> diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
> index f73290f..4bcc025 100644
> --- a/drivers/iio/chemical/Kconfig
> +++ b/drivers/iio/chemical/Kconfig
> @@ -5,15 +5,17 @@
>  menu "Chemical Sensors"
>  
>  config ATLAS_PH_SENSOR
> -	tristate "Atlas Scientific OEM pH-SM sensor"
> +	tristate "Atlas Scientific OEM SM sensors"
>  	depends on I2C
>  	select REGMAP_I2C
>  	select IIO_BUFFER
>  	select IIO_TRIGGERED_BUFFER
>  	select IRQ_WORK
>  	help
> -	 Say Y here to build I2C interface support for the Atlas
> -	 Scientific OEM pH-SM sensor.
> +	 Say Y here to build I2C interface support for the following
> +	 Atlas Scientific OEM SM sensors:
> +	    * pH SM sensor
> +	    * EC SM sensor
>  
>  	 To compile this driver as module, choose M here: the
>  	 module will be called atlas-ph-sensor.
> diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c
> index e85477c..02e85db 100644
> --- a/drivers/iio/chemical/atlas-ph-sensor.c
> +++ b/drivers/iio/chemical/atlas-ph-sensor.c
> @@ -50,13 +50,28 @@
>  #define ATLAS_REG_PH_CALIB_STATUS_MID	BIT(1)
>  #define ATLAS_REG_PH_CALIB_STATUS_HIGH	BIT(2)
>  
> +#define ATLAS_REG_EC_CALIB_STATUS		0x0f
> +#define ATLAS_REG_EC_CALIB_STATUS_MASK		0x0f
> +#define ATLAS_REG_EC_CALIB_STATUS_DRY		BIT(0)
> +#define ATLAS_REG_EC_CALIB_STATUS_SINGLE	BIT(1)
> +#define ATLAS_REG_EC_CALIB_STATUS_LOW		BIT(2)
> +#define ATLAS_REG_EC_CALIB_STATUS_HIGH		BIT(3)
> +
>  #define ATLAS_REG_PH_TEMP_DATA		0x0e
>  #define ATLAS_REG_PH_DATA		0x16
>  
> +#define ATLAS_REG_EC_PROBE		0x08
> +#define ATLAS_REG_EC_TEMP_DATA		0x10
> +#define ATLAS_REG_EC_DATA		0x18
> +#define ATLAS_REG_TDS_DATA		0x1c
> +#define ATLAS_REG_PSS_DATA		0x20
> +
>  #define ATLAS_PH_INT_TIME_IN_US		450000
> +#define ATLAS_EC_INT_TIME_IN_US		650000
>  
>  enum {
>  	ATLAS_PH_SM,
> +	ATLAS_EC_SM,
>  };
>  
>  struct atlas_data {
> @@ -66,12 +81,13 @@ struct atlas_data {
>  	struct regmap *regmap;
>  	struct irq_work work;
>  
> -	__be32 buffer[4]; /* 32-bit pH data + 32-bit pad + 64-bit timestamp */
> +	__be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */
>  };
>  
>  static const struct regmap_range atlas_volatile_ranges[] = {
>  	regmap_reg_range(ATLAS_REG_INT_CONTROL, ATLAS_REG_INT_CONTROL),
>  	regmap_reg_range(ATLAS_REG_PH_DATA, ATLAS_REG_PH_DATA + 4),
> +	regmap_reg_range(ATLAS_REG_EC_DATA, ATLAS_REG_PSS_DATA + 4),
>  };
>  
>  static const struct regmap_access_table atlas_volatile_table = {
> @@ -86,7 +102,7 @@ static const struct regmap_config atlas_regmap_config = {
>  	.val_bits = 8,
>  
>  	.volatile_table = &atlas_volatile_table,
> -	.max_register = ATLAS_REG_PH_DATA + 4,
> +	.max_register = ATLAS_REG_PSS_DATA + 4,
>  	.cache_type = REGCACHE_RBTREE,
>  };
>  
> @@ -115,6 +131,50 @@ static const struct iio_chan_spec atlas_ph_channels[] = {
>  	},
>  };
>  
> +#define ATLAS_EC_CHANNEL(_idx, _addr) \
> +	{\
> +		.type = IIO_CONCENTRATION, \
> +		.indexed = 1, \
> +		.channel = _idx, \
> +		.address = _addr, \
> +		.info_mask_separate = \
> +			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
> +		.scan_index = _idx + 1, \
> +		.scan_type = { \
> +			.sign = 'u', \
> +			.realbits = 32, \
> +			.storagebits = 32, \
> +			.endianness = IIO_BE, \
> +		}, \
> +	}
> +
> +static const struct iio_chan_spec atlas_ec_channels[] = {
> +	{
> +		.type = IIO_ELECTRICALCONDUCTIVITY,
> +		.address = ATLAS_REG_EC_DATA,
> +		.info_mask_separate =
> +			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
> +		.scan_index = 0,
> +		.scan_type = {
> +			.sign = 'u',
> +			.realbits = 32,
> +			.storagebits = 32,
> +			.endianness = IIO_BE,
> +		},
> +	},
> +	ATLAS_EC_CHANNEL(0, ATLAS_REG_TDS_DATA),
> +	ATLAS_EC_CHANNEL(1, ATLAS_REG_PSS_DATA),
> +	IIO_CHAN_SOFT_TIMESTAMP(3),
> +	{
> +		.type = IIO_TEMP,
> +		.address = ATLAS_REG_EC_TEMP_DATA,
> +		.info_mask_separate =
> +			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
> +		.output = 1,
> +		.scan_index = -1
> +	},
> +};
> +
>  static int atlas_check_ph_calibration(struct atlas_data *data)
>  {
>  	struct device *dev = &data->client->dev;
> @@ -142,6 +202,44 @@ static int atlas_check_ph_calibration(struct atlas_data *data)
>  	return 0;
>  }
>  
> +static int atlas_check_ec_calibration(struct atlas_data *data)
> +{
> +	struct device *dev = &data->client->dev;
> +	int ret;
> +	unsigned int val;
> +
> +	ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &val, 2);
> +	if (ret)
> +		return ret;
> +
> +	dev_info(dev, "probe set to K = %d.%.2d", be16_to_cpu(val) / 100,
> +						 be16_to_cpu(val) % 100);
> +
> +	ret = regmap_read(data->regmap, ATLAS_REG_EC_CALIB_STATUS, &val);
> +	if (ret)
> +		return ret;
> +
> +	if (!(val & ATLAS_REG_EC_CALIB_STATUS_MASK)) {
> +		dev_warn(dev, "device has not been calibrated\n");
> +		return 0;
> +	}
> +
> +	if (!(val & ATLAS_REG_EC_CALIB_STATUS_DRY))
> +		dev_warn(dev, "device missing dry point calibration\n");
> +
> +	if (val & ATLAS_REG_EC_CALIB_STATUS_SINGLE) {
> +		dev_warn(dev, "device using single point calibration\n");
> +	} else {
> +		if (!(val & ATLAS_REG_EC_CALIB_STATUS_LOW))
> +			dev_warn(dev, "device missing low point calibration\n");
> +
> +		if (!(val & ATLAS_REG_EC_CALIB_STATUS_HIGH))
> +			dev_warn(dev, "device missing high point calibration\n");
> +	}
> +
> +	return 0;
> +}
> +
>  struct atlas_device {
>  	const struct iio_chan_spec *channels;
>  	int num_channels;
> @@ -159,6 +257,14 @@ static struct atlas_device atlas_devices[] = {
>  				.calibration = &atlas_check_ph_calibration,
>  				.delay = ATLAS_PH_INT_TIME_IN_US,
>  	},
> +	[ATLAS_EC_SM] = {
> +				.channels = atlas_ec_channels,
> +				.num_channels = 5,
> +				.data_reg = ATLAS_REG_EC_DATA,
> +				.calibration = &atlas_check_ec_calibration,
> +				.delay = ATLAS_EC_INT_TIME_IN_US,
> +	},
> +
>  };
>  
>  static int atlas_set_powermode(struct atlas_data *data, int on)
> @@ -294,6 +400,8 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
>  					      (u8 *) &reg, sizeof(reg));
>  			break;
>  		case IIO_PH:
> +		case IIO_CONCENTRATION:
> +		case IIO_ELECTRICALCONDUCTIVITY:
>  			mutex_lock(&indio_dev->mlock);
>  
>  			if (iio_buffer_enabled(indio_dev))
> @@ -324,6 +432,14 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
>  			*val = 1; /* 0.001 */
>  			*val2 = 1000;
>  			break;
> +		case IIO_ELECTRICALCONDUCTIVITY:
> +			*val = 1; /* 0.00001 */
> +			*val = 100000;
> +			break;
> +		case IIO_CONCENTRATION:
> +			*val = 0; /* 0.000000001 */
> +			*val2 = 1000;
> +			return IIO_VAL_INT_PLUS_NANO;
>  		default:
>  			return -EINVAL;
>  		}
> @@ -358,12 +474,14 @@ static const struct iio_info atlas_info = {
>  
>  static const struct i2c_device_id atlas_id[] = {
>  	{ "atlas-ph-sm", ATLAS_PH_SM},
> +	{ "atlas-ec-sm", ATLAS_EC_SM},
>  	{}
>  };
>  MODULE_DEVICE_TABLE(i2c, atlas_id);
>  
>  static const struct of_device_id atlas_dt_ids[] = {
>  	{ .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
> +	{ .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(of, atlas_dt_ids);
> 


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

end of thread, other threads:[~2016-05-29 19:05 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-05-25  4:29 [PATCH v3 0/3] atlas-ph-sensor: add conductivity sensor support Matt Ranostay
2016-05-25  4:29 ` [PATCH v3 1/3] iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips Matt Ranostay
2016-05-29 19:03   ` Jonathan Cameron
2016-05-25  4:29 ` [PATCH v3 2/3] iio: electricalconductivity: add IIO_ELECTRICALCONDUCTIVITY type Matt Ranostay
2016-05-29 19:04   ` Jonathan Cameron
2016-05-25  4:29 ` [PATCH v3 3/3] iio: chemical: atlas-ph-sensor: add EC feature Matt Ranostay
2016-05-29 19:05   ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).