162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * atlas-sensor.c - Support for Atlas Scientific OEM SM sensors 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015-2019 Konsulko Group 662306a36Sopenharmony_ci * Author: Matt Ranostay <matt.ranostay@konsulko.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/mutex.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/irq.h> 1662306a36Sopenharmony_ci#include <linux/irq_work.h> 1762306a36Sopenharmony_ci#include <linux/i2c.h> 1862306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1962306a36Sopenharmony_ci#include <linux/regmap.h> 2062306a36Sopenharmony_ci#include <linux/iio/iio.h> 2162306a36Sopenharmony_ci#include <linux/iio/buffer.h> 2262306a36Sopenharmony_ci#include <linux/iio/trigger.h> 2362306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 2462306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 2562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define ATLAS_REGMAP_NAME "atlas_regmap" 2862306a36Sopenharmony_ci#define ATLAS_DRV_NAME "atlas" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define ATLAS_REG_DEV_TYPE 0x00 3162306a36Sopenharmony_ci#define ATLAS_REG_DEV_VERSION 0x01 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define ATLAS_REG_INT_CONTROL 0x04 3462306a36Sopenharmony_ci#define ATLAS_REG_INT_CONTROL_EN BIT(3) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define ATLAS_REG_PWR_CONTROL 0x06 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS 0x0d 3962306a36Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS_MASK 0x07 4062306a36Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS_LOW BIT(0) 4162306a36Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS_MID BIT(1) 4262306a36Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS_HIGH BIT(2) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS 0x0f 4562306a36Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_MASK 0x0f 4662306a36Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_DRY BIT(0) 4762306a36Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_SINGLE BIT(1) 4862306a36Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_LOW BIT(2) 4962306a36Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_HIGH BIT(3) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define ATLAS_REG_DO_CALIB_STATUS 0x09 5262306a36Sopenharmony_ci#define ATLAS_REG_DO_CALIB_STATUS_MASK 0x03 5362306a36Sopenharmony_ci#define ATLAS_REG_DO_CALIB_STATUS_PRESSURE BIT(0) 5462306a36Sopenharmony_ci#define ATLAS_REG_DO_CALIB_STATUS_DO BIT(1) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define ATLAS_REG_RTD_DATA 0x0e 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define ATLAS_REG_PH_TEMP_DATA 0x0e 5962306a36Sopenharmony_ci#define ATLAS_REG_PH_DATA 0x16 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define ATLAS_REG_EC_PROBE 0x08 6262306a36Sopenharmony_ci#define ATLAS_REG_EC_TEMP_DATA 0x10 6362306a36Sopenharmony_ci#define ATLAS_REG_EC_DATA 0x18 6462306a36Sopenharmony_ci#define ATLAS_REG_TDS_DATA 0x1c 6562306a36Sopenharmony_ci#define ATLAS_REG_PSS_DATA 0x20 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define ATLAS_REG_ORP_CALIB_STATUS 0x0d 6862306a36Sopenharmony_ci#define ATLAS_REG_ORP_DATA 0x0e 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define ATLAS_REG_DO_TEMP_DATA 0x12 7162306a36Sopenharmony_ci#define ATLAS_REG_DO_DATA 0x22 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define ATLAS_PH_INT_TIME_IN_MS 450 7462306a36Sopenharmony_ci#define ATLAS_EC_INT_TIME_IN_MS 650 7562306a36Sopenharmony_ci#define ATLAS_ORP_INT_TIME_IN_MS 450 7662306a36Sopenharmony_ci#define ATLAS_DO_INT_TIME_IN_MS 450 7762306a36Sopenharmony_ci#define ATLAS_RTD_INT_TIME_IN_MS 450 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cienum { 8062306a36Sopenharmony_ci ATLAS_PH_SM, 8162306a36Sopenharmony_ci ATLAS_EC_SM, 8262306a36Sopenharmony_ci ATLAS_ORP_SM, 8362306a36Sopenharmony_ci ATLAS_DO_SM, 8462306a36Sopenharmony_ci ATLAS_RTD_SM, 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct atlas_data { 8862306a36Sopenharmony_ci struct i2c_client *client; 8962306a36Sopenharmony_ci struct iio_trigger *trig; 9062306a36Sopenharmony_ci struct atlas_device *chip; 9162306a36Sopenharmony_ci struct regmap *regmap; 9262306a36Sopenharmony_ci struct irq_work work; 9362306a36Sopenharmony_ci unsigned int interrupt_enabled; 9462306a36Sopenharmony_ci /* 96-bit data + 32-bit pad + 64-bit timestamp */ 9562306a36Sopenharmony_ci __be32 buffer[6] __aligned(8); 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const struct regmap_config atlas_regmap_config = { 9962306a36Sopenharmony_ci .name = ATLAS_REGMAP_NAME, 10062306a36Sopenharmony_ci .reg_bits = 8, 10162306a36Sopenharmony_ci .val_bits = 8, 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int atlas_buffer_num_channels(const struct iio_chan_spec *spec) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci int idx = 0; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci for (; spec->type != IIO_TIMESTAMP; spec++) 10962306a36Sopenharmony_ci idx++; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return idx; 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic const struct iio_chan_spec atlas_ph_channels[] = { 11562306a36Sopenharmony_ci { 11662306a36Sopenharmony_ci .type = IIO_PH, 11762306a36Sopenharmony_ci .address = ATLAS_REG_PH_DATA, 11862306a36Sopenharmony_ci .info_mask_separate = 11962306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 12062306a36Sopenharmony_ci .scan_index = 0, 12162306a36Sopenharmony_ci .scan_type = { 12262306a36Sopenharmony_ci .sign = 'u', 12362306a36Sopenharmony_ci .realbits = 32, 12462306a36Sopenharmony_ci .storagebits = 32, 12562306a36Sopenharmony_ci .endianness = IIO_BE, 12662306a36Sopenharmony_ci }, 12762306a36Sopenharmony_ci }, 12862306a36Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(1), 12962306a36Sopenharmony_ci { 13062306a36Sopenharmony_ci .type = IIO_TEMP, 13162306a36Sopenharmony_ci .address = ATLAS_REG_PH_TEMP_DATA, 13262306a36Sopenharmony_ci .info_mask_separate = 13362306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 13462306a36Sopenharmony_ci .output = 1, 13562306a36Sopenharmony_ci .scan_index = -1 13662306a36Sopenharmony_ci }, 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define ATLAS_CONCENTRATION_CHANNEL(_idx, _addr) \ 14062306a36Sopenharmony_ci {\ 14162306a36Sopenharmony_ci .type = IIO_CONCENTRATION, \ 14262306a36Sopenharmony_ci .indexed = 1, \ 14362306a36Sopenharmony_ci .channel = _idx, \ 14462306a36Sopenharmony_ci .address = _addr, \ 14562306a36Sopenharmony_ci .info_mask_separate = \ 14662306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \ 14762306a36Sopenharmony_ci .scan_index = _idx + 1, \ 14862306a36Sopenharmony_ci .scan_type = { \ 14962306a36Sopenharmony_ci .sign = 'u', \ 15062306a36Sopenharmony_ci .realbits = 32, \ 15162306a36Sopenharmony_ci .storagebits = 32, \ 15262306a36Sopenharmony_ci .endianness = IIO_BE, \ 15362306a36Sopenharmony_ci }, \ 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic const struct iio_chan_spec atlas_ec_channels[] = { 15762306a36Sopenharmony_ci { 15862306a36Sopenharmony_ci .type = IIO_ELECTRICALCONDUCTIVITY, 15962306a36Sopenharmony_ci .address = ATLAS_REG_EC_DATA, 16062306a36Sopenharmony_ci .info_mask_separate = 16162306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 16262306a36Sopenharmony_ci .scan_index = 0, 16362306a36Sopenharmony_ci .scan_type = { 16462306a36Sopenharmony_ci .sign = 'u', 16562306a36Sopenharmony_ci .realbits = 32, 16662306a36Sopenharmony_ci .storagebits = 32, 16762306a36Sopenharmony_ci .endianness = IIO_BE, 16862306a36Sopenharmony_ci }, 16962306a36Sopenharmony_ci }, 17062306a36Sopenharmony_ci ATLAS_CONCENTRATION_CHANNEL(0, ATLAS_REG_TDS_DATA), 17162306a36Sopenharmony_ci ATLAS_CONCENTRATION_CHANNEL(1, ATLAS_REG_PSS_DATA), 17262306a36Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(3), 17362306a36Sopenharmony_ci { 17462306a36Sopenharmony_ci .type = IIO_TEMP, 17562306a36Sopenharmony_ci .address = ATLAS_REG_EC_TEMP_DATA, 17662306a36Sopenharmony_ci .info_mask_separate = 17762306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 17862306a36Sopenharmony_ci .output = 1, 17962306a36Sopenharmony_ci .scan_index = -1 18062306a36Sopenharmony_ci }, 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic const struct iio_chan_spec atlas_orp_channels[] = { 18462306a36Sopenharmony_ci { 18562306a36Sopenharmony_ci .type = IIO_VOLTAGE, 18662306a36Sopenharmony_ci .address = ATLAS_REG_ORP_DATA, 18762306a36Sopenharmony_ci .info_mask_separate = 18862306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 18962306a36Sopenharmony_ci .scan_index = 0, 19062306a36Sopenharmony_ci .scan_type = { 19162306a36Sopenharmony_ci .sign = 's', 19262306a36Sopenharmony_ci .realbits = 32, 19362306a36Sopenharmony_ci .storagebits = 32, 19462306a36Sopenharmony_ci .endianness = IIO_BE, 19562306a36Sopenharmony_ci }, 19662306a36Sopenharmony_ci }, 19762306a36Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(1), 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic const struct iio_chan_spec atlas_do_channels[] = { 20162306a36Sopenharmony_ci { 20262306a36Sopenharmony_ci .type = IIO_CONCENTRATION, 20362306a36Sopenharmony_ci .address = ATLAS_REG_DO_DATA, 20462306a36Sopenharmony_ci .info_mask_separate = 20562306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 20662306a36Sopenharmony_ci .scan_index = 0, 20762306a36Sopenharmony_ci .scan_type = { 20862306a36Sopenharmony_ci .sign = 'u', 20962306a36Sopenharmony_ci .realbits = 32, 21062306a36Sopenharmony_ci .storagebits = 32, 21162306a36Sopenharmony_ci .endianness = IIO_BE, 21262306a36Sopenharmony_ci }, 21362306a36Sopenharmony_ci }, 21462306a36Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(1), 21562306a36Sopenharmony_ci { 21662306a36Sopenharmony_ci .type = IIO_TEMP, 21762306a36Sopenharmony_ci .address = ATLAS_REG_DO_TEMP_DATA, 21862306a36Sopenharmony_ci .info_mask_separate = 21962306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 22062306a36Sopenharmony_ci .output = 1, 22162306a36Sopenharmony_ci .scan_index = -1 22262306a36Sopenharmony_ci }, 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic const struct iio_chan_spec atlas_rtd_channels[] = { 22662306a36Sopenharmony_ci { 22762306a36Sopenharmony_ci .type = IIO_TEMP, 22862306a36Sopenharmony_ci .address = ATLAS_REG_RTD_DATA, 22962306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 23062306a36Sopenharmony_ci .scan_index = 0, 23162306a36Sopenharmony_ci .scan_type = { 23262306a36Sopenharmony_ci .sign = 's', 23362306a36Sopenharmony_ci .realbits = 32, 23462306a36Sopenharmony_ci .storagebits = 32, 23562306a36Sopenharmony_ci .endianness = IIO_BE, 23662306a36Sopenharmony_ci }, 23762306a36Sopenharmony_ci }, 23862306a36Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(1), 23962306a36Sopenharmony_ci}; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int atlas_check_ph_calibration(struct atlas_data *data) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct device *dev = &data->client->dev; 24462306a36Sopenharmony_ci int ret; 24562306a36Sopenharmony_ci unsigned int val; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci ret = regmap_read(data->regmap, ATLAS_REG_PH_CALIB_STATUS, &val); 24862306a36Sopenharmony_ci if (ret) 24962306a36Sopenharmony_ci return ret; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!(val & ATLAS_REG_PH_CALIB_STATUS_MASK)) { 25262306a36Sopenharmony_ci dev_warn(dev, "device has not been calibrated\n"); 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (!(val & ATLAS_REG_PH_CALIB_STATUS_LOW)) 25762306a36Sopenharmony_ci dev_warn(dev, "device missing low point calibration\n"); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (!(val & ATLAS_REG_PH_CALIB_STATUS_MID)) 26062306a36Sopenharmony_ci dev_warn(dev, "device missing mid point calibration\n"); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (!(val & ATLAS_REG_PH_CALIB_STATUS_HIGH)) 26362306a36Sopenharmony_ci dev_warn(dev, "device missing high point calibration\n"); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int atlas_check_ec_calibration(struct atlas_data *data) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct device *dev = &data->client->dev; 27162306a36Sopenharmony_ci int ret; 27262306a36Sopenharmony_ci unsigned int val; 27362306a36Sopenharmony_ci __be16 rval; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &rval, 2); 27662306a36Sopenharmony_ci if (ret) 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci val = be16_to_cpu(rval); 28062306a36Sopenharmony_ci dev_info(dev, "probe set to K = %d.%.2d", val / 100, val % 100); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci ret = regmap_read(data->regmap, ATLAS_REG_EC_CALIB_STATUS, &val); 28362306a36Sopenharmony_ci if (ret) 28462306a36Sopenharmony_ci return ret; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (!(val & ATLAS_REG_EC_CALIB_STATUS_MASK)) { 28762306a36Sopenharmony_ci dev_warn(dev, "device has not been calibrated\n"); 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (!(val & ATLAS_REG_EC_CALIB_STATUS_DRY)) 29262306a36Sopenharmony_ci dev_warn(dev, "device missing dry point calibration\n"); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (val & ATLAS_REG_EC_CALIB_STATUS_SINGLE) { 29562306a36Sopenharmony_ci dev_warn(dev, "device using single point calibration\n"); 29662306a36Sopenharmony_ci } else { 29762306a36Sopenharmony_ci if (!(val & ATLAS_REG_EC_CALIB_STATUS_LOW)) 29862306a36Sopenharmony_ci dev_warn(dev, "device missing low point calibration\n"); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!(val & ATLAS_REG_EC_CALIB_STATUS_HIGH)) 30162306a36Sopenharmony_ci dev_warn(dev, "device missing high point calibration\n"); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int atlas_check_orp_calibration(struct atlas_data *data) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct device *dev = &data->client->dev; 31062306a36Sopenharmony_ci int ret; 31162306a36Sopenharmony_ci unsigned int val; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci ret = regmap_read(data->regmap, ATLAS_REG_ORP_CALIB_STATUS, &val); 31462306a36Sopenharmony_ci if (ret) 31562306a36Sopenharmony_ci return ret; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (!val) 31862306a36Sopenharmony_ci dev_warn(dev, "device has not been calibrated\n"); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int atlas_check_do_calibration(struct atlas_data *data) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct device *dev = &data->client->dev; 32662306a36Sopenharmony_ci int ret; 32762306a36Sopenharmony_ci unsigned int val; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci ret = regmap_read(data->regmap, ATLAS_REG_DO_CALIB_STATUS, &val); 33062306a36Sopenharmony_ci if (ret) 33162306a36Sopenharmony_ci return ret; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (!(val & ATLAS_REG_DO_CALIB_STATUS_MASK)) { 33462306a36Sopenharmony_ci dev_warn(dev, "device has not been calibrated\n"); 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (!(val & ATLAS_REG_DO_CALIB_STATUS_PRESSURE)) 33962306a36Sopenharmony_ci dev_warn(dev, "device missing atmospheric pressure calibration\n"); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!(val & ATLAS_REG_DO_CALIB_STATUS_DO)) 34262306a36Sopenharmony_ci dev_warn(dev, "device missing dissolved oxygen calibration\n"); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistruct atlas_device { 34862306a36Sopenharmony_ci const struct iio_chan_spec *channels; 34962306a36Sopenharmony_ci int num_channels; 35062306a36Sopenharmony_ci int data_reg; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci int (*calibration)(struct atlas_data *data); 35362306a36Sopenharmony_ci int delay; 35462306a36Sopenharmony_ci}; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic struct atlas_device atlas_devices[] = { 35762306a36Sopenharmony_ci [ATLAS_PH_SM] = { 35862306a36Sopenharmony_ci .channels = atlas_ph_channels, 35962306a36Sopenharmony_ci .num_channels = 3, 36062306a36Sopenharmony_ci .data_reg = ATLAS_REG_PH_DATA, 36162306a36Sopenharmony_ci .calibration = &atlas_check_ph_calibration, 36262306a36Sopenharmony_ci .delay = ATLAS_PH_INT_TIME_IN_MS, 36362306a36Sopenharmony_ci }, 36462306a36Sopenharmony_ci [ATLAS_EC_SM] = { 36562306a36Sopenharmony_ci .channels = atlas_ec_channels, 36662306a36Sopenharmony_ci .num_channels = 5, 36762306a36Sopenharmony_ci .data_reg = ATLAS_REG_EC_DATA, 36862306a36Sopenharmony_ci .calibration = &atlas_check_ec_calibration, 36962306a36Sopenharmony_ci .delay = ATLAS_EC_INT_TIME_IN_MS, 37062306a36Sopenharmony_ci }, 37162306a36Sopenharmony_ci [ATLAS_ORP_SM] = { 37262306a36Sopenharmony_ci .channels = atlas_orp_channels, 37362306a36Sopenharmony_ci .num_channels = 2, 37462306a36Sopenharmony_ci .data_reg = ATLAS_REG_ORP_DATA, 37562306a36Sopenharmony_ci .calibration = &atlas_check_orp_calibration, 37662306a36Sopenharmony_ci .delay = ATLAS_ORP_INT_TIME_IN_MS, 37762306a36Sopenharmony_ci }, 37862306a36Sopenharmony_ci [ATLAS_DO_SM] = { 37962306a36Sopenharmony_ci .channels = atlas_do_channels, 38062306a36Sopenharmony_ci .num_channels = 3, 38162306a36Sopenharmony_ci .data_reg = ATLAS_REG_DO_DATA, 38262306a36Sopenharmony_ci .calibration = &atlas_check_do_calibration, 38362306a36Sopenharmony_ci .delay = ATLAS_DO_INT_TIME_IN_MS, 38462306a36Sopenharmony_ci }, 38562306a36Sopenharmony_ci [ATLAS_RTD_SM] = { 38662306a36Sopenharmony_ci .channels = atlas_rtd_channels, 38762306a36Sopenharmony_ci .num_channels = 2, 38862306a36Sopenharmony_ci .data_reg = ATLAS_REG_RTD_DATA, 38962306a36Sopenharmony_ci .delay = ATLAS_RTD_INT_TIME_IN_MS, 39062306a36Sopenharmony_ci }, 39162306a36Sopenharmony_ci}; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int atlas_set_powermode(struct atlas_data *data, int on) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci return regmap_write(data->regmap, ATLAS_REG_PWR_CONTROL, on); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int atlas_set_interrupt(struct atlas_data *data, bool state) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci if (!data->interrupt_enabled) 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return regmap_update_bits(data->regmap, ATLAS_REG_INT_CONTROL, 40462306a36Sopenharmony_ci ATLAS_REG_INT_CONTROL_EN, 40562306a36Sopenharmony_ci state ? ATLAS_REG_INT_CONTROL_EN : 0); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int atlas_buffer_postenable(struct iio_dev *indio_dev) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct atlas_data *data = iio_priv(indio_dev); 41162306a36Sopenharmony_ci int ret; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(&data->client->dev); 41462306a36Sopenharmony_ci if (ret) 41562306a36Sopenharmony_ci return ret; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return atlas_set_interrupt(data, true); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int atlas_buffer_predisable(struct iio_dev *indio_dev) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct atlas_data *data = iio_priv(indio_dev); 42362306a36Sopenharmony_ci int ret; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci ret = atlas_set_interrupt(data, false); 42662306a36Sopenharmony_ci if (ret) 42762306a36Sopenharmony_ci return ret; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci pm_runtime_mark_last_busy(&data->client->dev); 43062306a36Sopenharmony_ci ret = pm_runtime_put_autosuspend(&data->client->dev); 43162306a36Sopenharmony_ci if (ret) 43262306a36Sopenharmony_ci return ret; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const struct iio_buffer_setup_ops atlas_buffer_setup_ops = { 43862306a36Sopenharmony_ci .postenable = atlas_buffer_postenable, 43962306a36Sopenharmony_ci .predisable = atlas_buffer_predisable, 44062306a36Sopenharmony_ci}; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic void atlas_work_handler(struct irq_work *work) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct atlas_data *data = container_of(work, struct atlas_data, work); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci iio_trigger_poll(data->trig); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic irqreturn_t atlas_trigger_handler(int irq, void *private) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct iio_poll_func *pf = private; 45262306a36Sopenharmony_ci struct iio_dev *indio_dev = pf->indio_dev; 45362306a36Sopenharmony_ci struct atlas_data *data = iio_priv(indio_dev); 45462306a36Sopenharmony_ci int channels = atlas_buffer_num_channels(data->chip->channels); 45562306a36Sopenharmony_ci int ret; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci ret = regmap_bulk_read(data->regmap, data->chip->data_reg, 45862306a36Sopenharmony_ci &data->buffer, sizeof(__be32) * channels); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (!ret) 46162306a36Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, 46262306a36Sopenharmony_ci iio_get_time_ns(indio_dev)); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci return IRQ_HANDLED; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic irqreturn_t atlas_interrupt_handler(int irq, void *private) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct iio_dev *indio_dev = private; 47262306a36Sopenharmony_ci struct atlas_data *data = iio_priv(indio_dev); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci irq_work_queue(&data->work); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return IRQ_HANDLED; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct device *dev = &data->client->dev; 48262306a36Sopenharmony_ci int suspended = pm_runtime_suspended(dev); 48362306a36Sopenharmony_ci int ret; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 48662306a36Sopenharmony_ci if (ret) 48762306a36Sopenharmony_ci return ret; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (suspended) 49062306a36Sopenharmony_ci msleep(data->chip->delay); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci ret = regmap_bulk_read(data->regmap, reg, val, sizeof(*val)); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 49562306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return ret; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int atlas_read_raw(struct iio_dev *indio_dev, 50162306a36Sopenharmony_ci struct iio_chan_spec const *chan, 50262306a36Sopenharmony_ci int *val, int *val2, long mask) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct atlas_data *data = iio_priv(indio_dev); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci switch (mask) { 50762306a36Sopenharmony_ci case IIO_CHAN_INFO_PROCESSED: 50862306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: { 50962306a36Sopenharmony_ci int ret; 51062306a36Sopenharmony_ci __be32 reg; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci switch (chan->type) { 51362306a36Sopenharmony_ci case IIO_TEMP: 51462306a36Sopenharmony_ci ret = regmap_bulk_read(data->regmap, chan->address, 51562306a36Sopenharmony_ci ®, sizeof(reg)); 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci case IIO_PH: 51862306a36Sopenharmony_ci case IIO_CONCENTRATION: 51962306a36Sopenharmony_ci case IIO_ELECTRICALCONDUCTIVITY: 52062306a36Sopenharmony_ci case IIO_VOLTAGE: 52162306a36Sopenharmony_ci ret = iio_device_claim_direct_mode(indio_dev); 52262306a36Sopenharmony_ci if (ret) 52362306a36Sopenharmony_ci return ret; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ret = atlas_read_measurement(data, chan->address, ®); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci default: 53062306a36Sopenharmony_ci ret = -EINVAL; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (!ret) { 53462306a36Sopenharmony_ci *val = be32_to_cpu(reg); 53562306a36Sopenharmony_ci ret = IIO_VAL_INT; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci return ret; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 54062306a36Sopenharmony_ci switch (chan->type) { 54162306a36Sopenharmony_ci case IIO_TEMP: 54262306a36Sopenharmony_ci *val = 10; 54362306a36Sopenharmony_ci return IIO_VAL_INT; 54462306a36Sopenharmony_ci case IIO_PH: 54562306a36Sopenharmony_ci *val = 1; /* 0.001 */ 54662306a36Sopenharmony_ci *val2 = 1000; 54762306a36Sopenharmony_ci break; 54862306a36Sopenharmony_ci case IIO_ELECTRICALCONDUCTIVITY: 54962306a36Sopenharmony_ci *val = 1; /* 0.00001 */ 55062306a36Sopenharmony_ci *val2 = 100000; 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci case IIO_CONCENTRATION: 55362306a36Sopenharmony_ci *val = 0; /* 0.000000001 */ 55462306a36Sopenharmony_ci *val2 = 1000; 55562306a36Sopenharmony_ci return IIO_VAL_INT_PLUS_NANO; 55662306a36Sopenharmony_ci case IIO_VOLTAGE: 55762306a36Sopenharmony_ci *val = 1; /* 0.1 */ 55862306a36Sopenharmony_ci *val2 = 10; 55962306a36Sopenharmony_ci break; 56062306a36Sopenharmony_ci default: 56162306a36Sopenharmony_ci return -EINVAL; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci return IIO_VAL_FRACTIONAL; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci return -EINVAL; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic int atlas_write_raw(struct iio_dev *indio_dev, 57062306a36Sopenharmony_ci struct iio_chan_spec const *chan, 57162306a36Sopenharmony_ci int val, int val2, long mask) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct atlas_data *data = iio_priv(indio_dev); 57462306a36Sopenharmony_ci __be32 reg = cpu_to_be32(val / 10); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (val2 != 0 || val < 0 || val > 20000) 57762306a36Sopenharmony_ci return -EINVAL; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_TEMP) 58062306a36Sopenharmony_ci return -EINVAL; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return regmap_bulk_write(data->regmap, chan->address, 58362306a36Sopenharmony_ci ®, sizeof(reg)); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic const struct iio_info atlas_info = { 58762306a36Sopenharmony_ci .read_raw = atlas_read_raw, 58862306a36Sopenharmony_ci .write_raw = atlas_write_raw, 58962306a36Sopenharmony_ci}; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic const struct i2c_device_id atlas_id[] = { 59262306a36Sopenharmony_ci { "atlas-ph-sm", ATLAS_PH_SM }, 59362306a36Sopenharmony_ci { "atlas-ec-sm", ATLAS_EC_SM }, 59462306a36Sopenharmony_ci { "atlas-orp-sm", ATLAS_ORP_SM }, 59562306a36Sopenharmony_ci { "atlas-do-sm", ATLAS_DO_SM }, 59662306a36Sopenharmony_ci { "atlas-rtd-sm", ATLAS_RTD_SM }, 59762306a36Sopenharmony_ci {} 59862306a36Sopenharmony_ci}; 59962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, atlas_id); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic const struct of_device_id atlas_dt_ids[] = { 60262306a36Sopenharmony_ci { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, }, 60362306a36Sopenharmony_ci { .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, }, 60462306a36Sopenharmony_ci { .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, }, 60562306a36Sopenharmony_ci { .compatible = "atlas,do-sm", .data = (void *)ATLAS_DO_SM, }, 60662306a36Sopenharmony_ci { .compatible = "atlas,rtd-sm", .data = (void *)ATLAS_RTD_SM, }, 60762306a36Sopenharmony_ci { } 60862306a36Sopenharmony_ci}; 60962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, atlas_dt_ids); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic int atlas_probe(struct i2c_client *client) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci const struct i2c_device_id *id = i2c_client_get_device_id(client); 61462306a36Sopenharmony_ci struct atlas_data *data; 61562306a36Sopenharmony_ci struct atlas_device *chip; 61662306a36Sopenharmony_ci struct iio_trigger *trig; 61762306a36Sopenharmony_ci struct iio_dev *indio_dev; 61862306a36Sopenharmony_ci int ret; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 62162306a36Sopenharmony_ci if (!indio_dev) 62262306a36Sopenharmony_ci return -ENOMEM; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (!dev_fwnode(&client->dev)) 62562306a36Sopenharmony_ci chip = &atlas_devices[id->driver_data]; 62662306a36Sopenharmony_ci else 62762306a36Sopenharmony_ci chip = &atlas_devices[(unsigned long)device_get_match_data(&client->dev)]; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci indio_dev->info = &atlas_info; 63062306a36Sopenharmony_ci indio_dev->name = ATLAS_DRV_NAME; 63162306a36Sopenharmony_ci indio_dev->channels = chip->channels; 63262306a36Sopenharmony_ci indio_dev->num_channels = chip->num_channels; 63362306a36Sopenharmony_ci indio_dev->modes = INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", 63662306a36Sopenharmony_ci indio_dev->name, iio_device_id(indio_dev)); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (!trig) 63962306a36Sopenharmony_ci return -ENOMEM; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci data = iio_priv(indio_dev); 64262306a36Sopenharmony_ci data->client = client; 64362306a36Sopenharmony_ci data->trig = trig; 64462306a36Sopenharmony_ci data->chip = chip; 64562306a36Sopenharmony_ci iio_trigger_set_drvdata(trig, indio_dev); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci i2c_set_clientdata(client, indio_dev); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci data->regmap = devm_regmap_init_i2c(client, &atlas_regmap_config); 65062306a36Sopenharmony_ci if (IS_ERR(data->regmap)) { 65162306a36Sopenharmony_ci dev_err(&client->dev, "regmap initialization failed\n"); 65262306a36Sopenharmony_ci return PTR_ERR(data->regmap); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci ret = pm_runtime_set_active(&client->dev); 65662306a36Sopenharmony_ci if (ret) 65762306a36Sopenharmony_ci return ret; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci ret = chip->calibration(data); 66062306a36Sopenharmony_ci if (ret) 66162306a36Sopenharmony_ci return ret; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci ret = iio_trigger_register(trig); 66462306a36Sopenharmony_ci if (ret) { 66562306a36Sopenharmony_ci dev_err(&client->dev, "failed to register trigger\n"); 66662306a36Sopenharmony_ci return ret; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, 67062306a36Sopenharmony_ci &atlas_trigger_handler, &atlas_buffer_setup_ops); 67162306a36Sopenharmony_ci if (ret) { 67262306a36Sopenharmony_ci dev_err(&client->dev, "cannot setup iio trigger\n"); 67362306a36Sopenharmony_ci goto unregister_trigger; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci init_irq_work(&data->work, atlas_work_handler); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (client->irq > 0) { 67962306a36Sopenharmony_ci /* interrupt pin toggles on new conversion */ 68062306a36Sopenharmony_ci ret = devm_request_threaded_irq(&client->dev, client->irq, 68162306a36Sopenharmony_ci NULL, atlas_interrupt_handler, 68262306a36Sopenharmony_ci IRQF_TRIGGER_RISING | 68362306a36Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 68462306a36Sopenharmony_ci "atlas_irq", 68562306a36Sopenharmony_ci indio_dev); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (ret) 68862306a36Sopenharmony_ci dev_warn(&client->dev, 68962306a36Sopenharmony_ci "request irq (%d) failed\n", client->irq); 69062306a36Sopenharmony_ci else 69162306a36Sopenharmony_ci data->interrupt_enabled = 1; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci ret = atlas_set_powermode(data, 1); 69562306a36Sopenharmony_ci if (ret) { 69662306a36Sopenharmony_ci dev_err(&client->dev, "cannot power device on"); 69762306a36Sopenharmony_ci goto unregister_buffer; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci pm_runtime_enable(&client->dev); 70162306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(&client->dev, 2500); 70262306a36Sopenharmony_ci pm_runtime_use_autosuspend(&client->dev); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ret = iio_device_register(indio_dev); 70562306a36Sopenharmony_ci if (ret) { 70662306a36Sopenharmony_ci dev_err(&client->dev, "unable to register device\n"); 70762306a36Sopenharmony_ci goto unregister_pm; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ciunregister_pm: 71362306a36Sopenharmony_ci pm_runtime_disable(&client->dev); 71462306a36Sopenharmony_ci atlas_set_powermode(data, 0); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ciunregister_buffer: 71762306a36Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ciunregister_trigger: 72062306a36Sopenharmony_ci iio_trigger_unregister(data->trig); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return ret; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic void atlas_remove(struct i2c_client *client) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct iio_dev *indio_dev = i2c_get_clientdata(client); 72862306a36Sopenharmony_ci struct atlas_data *data = iio_priv(indio_dev); 72962306a36Sopenharmony_ci int ret; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci iio_device_unregister(indio_dev); 73262306a36Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 73362306a36Sopenharmony_ci iio_trigger_unregister(data->trig); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci pm_runtime_disable(&client->dev); 73662306a36Sopenharmony_ci pm_runtime_set_suspended(&client->dev); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci ret = atlas_set_powermode(data, 0); 73962306a36Sopenharmony_ci if (ret) 74062306a36Sopenharmony_ci dev_err(&client->dev, "Failed to power down device (%pe)\n", 74162306a36Sopenharmony_ci ERR_PTR(ret)); 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic int atlas_runtime_suspend(struct device *dev) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct atlas_data *data = 74762306a36Sopenharmony_ci iio_priv(i2c_get_clientdata(to_i2c_client(dev))); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci return atlas_set_powermode(data, 0); 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic int atlas_runtime_resume(struct device *dev) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct atlas_data *data = 75562306a36Sopenharmony_ci iio_priv(i2c_get_clientdata(to_i2c_client(dev))); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return atlas_set_powermode(data, 1); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic const struct dev_pm_ops atlas_pm_ops = { 76162306a36Sopenharmony_ci RUNTIME_PM_OPS(atlas_runtime_suspend, atlas_runtime_resume, NULL) 76262306a36Sopenharmony_ci}; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic struct i2c_driver atlas_driver = { 76562306a36Sopenharmony_ci .driver = { 76662306a36Sopenharmony_ci .name = ATLAS_DRV_NAME, 76762306a36Sopenharmony_ci .of_match_table = atlas_dt_ids, 76862306a36Sopenharmony_ci .pm = pm_ptr(&atlas_pm_ops), 76962306a36Sopenharmony_ci }, 77062306a36Sopenharmony_ci .probe = atlas_probe, 77162306a36Sopenharmony_ci .remove = atlas_remove, 77262306a36Sopenharmony_ci .id_table = atlas_id, 77362306a36Sopenharmony_ci}; 77462306a36Sopenharmony_cimodule_i2c_driver(atlas_driver); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ciMODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); 77762306a36Sopenharmony_ciMODULE_DESCRIPTION("Atlas Scientific SM sensors"); 77862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 779