Loading Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt 0 → 100644 +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>; }; drivers/iio/chemical/Kconfig +5 −3 Original line number Diff line number Diff line Loading @@ -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. Loading drivers/iio/chemical/atlas-ph-sensor.c +120 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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 = { Loading @@ -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, }; Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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) Loading Loading @@ -294,6 +400,8 @@ static int atlas_read_raw(struct iio_dev *indio_dev, (u8 *) ®, sizeof(reg)); break; case IIO_PH: case IIO_CONCENTRATION: case IIO_ELECTRICALCONDUCTIVITY: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) Loading Loading @@ -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; } Loading Loading @@ -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); Loading Loading
Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt 0 → 100644 +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>; };
drivers/iio/chemical/Kconfig +5 −3 Original line number Diff line number Diff line Loading @@ -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. Loading
drivers/iio/chemical/atlas-ph-sensor.c +120 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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 = { Loading @@ -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, }; Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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) Loading Loading @@ -294,6 +400,8 @@ static int atlas_read_raw(struct iio_dev *indio_dev, (u8 *) ®, sizeof(reg)); break; case IIO_PH: case IIO_CONCENTRATION: case IIO_ELECTRICALCONDUCTIVITY: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) Loading Loading @@ -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; } Loading Loading @@ -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); Loading