Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8dd92bf authored by Matt Ranostay's avatar Matt Ranostay Committed by Jonathan Cameron
Browse files

iio: chemical: atlas-ph-sensor: add EC feature

parent 4b9d2090
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
* 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>;
};
+5 −3
Original line number Diff line number Diff line
@@ -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.
+120 −2
Original line number Diff line number Diff line
@@ -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);