18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * atlas-sensor.c - Support for Atlas Scientific OEM SM sensors
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015-2019 Konsulko Group
68c2ecf20Sopenharmony_ci * Author: Matt Ranostay <matt.ranostay@konsulko.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/mutex.h>
148c2ecf20Sopenharmony_ci#include <linux/err.h>
158c2ecf20Sopenharmony_ci#include <linux/irq.h>
168c2ecf20Sopenharmony_ci#include <linux/irq_work.h>
178c2ecf20Sopenharmony_ci#include <linux/i2c.h>
188c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h>
198c2ecf20Sopenharmony_ci#include <linux/regmap.h>
208c2ecf20Sopenharmony_ci#include <linux/iio/iio.h>
218c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h>
228c2ecf20Sopenharmony_ci#include <linux/iio/trigger.h>
238c2ecf20Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
248c2ecf20Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
258c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define ATLAS_REGMAP_NAME	"atlas_regmap"
288c2ecf20Sopenharmony_ci#define ATLAS_DRV_NAME		"atlas"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define ATLAS_REG_DEV_TYPE		0x00
318c2ecf20Sopenharmony_ci#define ATLAS_REG_DEV_VERSION		0x01
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define ATLAS_REG_INT_CONTROL		0x04
348c2ecf20Sopenharmony_ci#define ATLAS_REG_INT_CONTROL_EN	BIT(3)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define ATLAS_REG_PWR_CONTROL		0x06
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS	0x0d
398c2ecf20Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS_MASK	0x07
408c2ecf20Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS_LOW	BIT(0)
418c2ecf20Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS_MID	BIT(1)
428c2ecf20Sopenharmony_ci#define ATLAS_REG_PH_CALIB_STATUS_HIGH	BIT(2)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS		0x0f
458c2ecf20Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_MASK		0x0f
468c2ecf20Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_DRY		BIT(0)
478c2ecf20Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_SINGLE	BIT(1)
488c2ecf20Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_LOW		BIT(2)
498c2ecf20Sopenharmony_ci#define ATLAS_REG_EC_CALIB_STATUS_HIGH		BIT(3)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define ATLAS_REG_DO_CALIB_STATUS		0x09
528c2ecf20Sopenharmony_ci#define ATLAS_REG_DO_CALIB_STATUS_MASK		0x03
538c2ecf20Sopenharmony_ci#define ATLAS_REG_DO_CALIB_STATUS_PRESSURE	BIT(0)
548c2ecf20Sopenharmony_ci#define ATLAS_REG_DO_CALIB_STATUS_DO		BIT(1)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define ATLAS_REG_RTD_DATA		0x0e
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define ATLAS_REG_PH_TEMP_DATA		0x0e
598c2ecf20Sopenharmony_ci#define ATLAS_REG_PH_DATA		0x16
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define ATLAS_REG_EC_PROBE		0x08
628c2ecf20Sopenharmony_ci#define ATLAS_REG_EC_TEMP_DATA		0x10
638c2ecf20Sopenharmony_ci#define ATLAS_REG_EC_DATA		0x18
648c2ecf20Sopenharmony_ci#define ATLAS_REG_TDS_DATA		0x1c
658c2ecf20Sopenharmony_ci#define ATLAS_REG_PSS_DATA		0x20
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define ATLAS_REG_ORP_CALIB_STATUS	0x0d
688c2ecf20Sopenharmony_ci#define ATLAS_REG_ORP_DATA		0x0e
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define ATLAS_REG_DO_TEMP_DATA		0x12
718c2ecf20Sopenharmony_ci#define ATLAS_REG_DO_DATA		0x22
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define ATLAS_PH_INT_TIME_IN_MS		450
748c2ecf20Sopenharmony_ci#define ATLAS_EC_INT_TIME_IN_MS		650
758c2ecf20Sopenharmony_ci#define ATLAS_ORP_INT_TIME_IN_MS	450
768c2ecf20Sopenharmony_ci#define ATLAS_DO_INT_TIME_IN_MS		450
778c2ecf20Sopenharmony_ci#define ATLAS_RTD_INT_TIME_IN_MS	450
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cienum {
808c2ecf20Sopenharmony_ci	ATLAS_PH_SM,
818c2ecf20Sopenharmony_ci	ATLAS_EC_SM,
828c2ecf20Sopenharmony_ci	ATLAS_ORP_SM,
838c2ecf20Sopenharmony_ci	ATLAS_DO_SM,
848c2ecf20Sopenharmony_ci	ATLAS_RTD_SM,
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistruct atlas_data {
888c2ecf20Sopenharmony_ci	struct i2c_client *client;
898c2ecf20Sopenharmony_ci	struct iio_trigger *trig;
908c2ecf20Sopenharmony_ci	struct atlas_device *chip;
918c2ecf20Sopenharmony_ci	struct regmap *regmap;
928c2ecf20Sopenharmony_ci	struct irq_work work;
938c2ecf20Sopenharmony_ci	unsigned int interrupt_enabled;
948c2ecf20Sopenharmony_ci	/* 96-bit data + 32-bit pad + 64-bit timestamp */
958c2ecf20Sopenharmony_ci	__be32 buffer[6] __aligned(8);
968c2ecf20Sopenharmony_ci};
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic const struct regmap_config atlas_regmap_config = {
998c2ecf20Sopenharmony_ci	.name = ATLAS_REGMAP_NAME,
1008c2ecf20Sopenharmony_ci	.reg_bits = 8,
1018c2ecf20Sopenharmony_ci	.val_bits = 8,
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic int atlas_buffer_num_channels(const struct iio_chan_spec *spec)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	int idx = 0;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	for (; spec->type != IIO_TIMESTAMP; spec++)
1098c2ecf20Sopenharmony_ci		idx++;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return idx;
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic const struct iio_chan_spec atlas_ph_channels[] = {
1158c2ecf20Sopenharmony_ci	{
1168c2ecf20Sopenharmony_ci		.type = IIO_PH,
1178c2ecf20Sopenharmony_ci		.address = ATLAS_REG_PH_DATA,
1188c2ecf20Sopenharmony_ci		.info_mask_separate =
1198c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
1208c2ecf20Sopenharmony_ci		.scan_index = 0,
1218c2ecf20Sopenharmony_ci		.scan_type = {
1228c2ecf20Sopenharmony_ci			.sign = 'u',
1238c2ecf20Sopenharmony_ci			.realbits = 32,
1248c2ecf20Sopenharmony_ci			.storagebits = 32,
1258c2ecf20Sopenharmony_ci			.endianness = IIO_BE,
1268c2ecf20Sopenharmony_ci		},
1278c2ecf20Sopenharmony_ci	},
1288c2ecf20Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(1),
1298c2ecf20Sopenharmony_ci	{
1308c2ecf20Sopenharmony_ci		.type = IIO_TEMP,
1318c2ecf20Sopenharmony_ci		.address = ATLAS_REG_PH_TEMP_DATA,
1328c2ecf20Sopenharmony_ci		.info_mask_separate =
1338c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
1348c2ecf20Sopenharmony_ci		.output = 1,
1358c2ecf20Sopenharmony_ci		.scan_index = -1
1368c2ecf20Sopenharmony_ci	},
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#define ATLAS_CONCENTRATION_CHANNEL(_idx, _addr) \
1408c2ecf20Sopenharmony_ci	{\
1418c2ecf20Sopenharmony_ci		.type = IIO_CONCENTRATION, \
1428c2ecf20Sopenharmony_ci		.indexed = 1, \
1438c2ecf20Sopenharmony_ci		.channel = _idx, \
1448c2ecf20Sopenharmony_ci		.address = _addr, \
1458c2ecf20Sopenharmony_ci		.info_mask_separate = \
1468c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
1478c2ecf20Sopenharmony_ci		.scan_index = _idx + 1, \
1488c2ecf20Sopenharmony_ci		.scan_type = { \
1498c2ecf20Sopenharmony_ci			.sign = 'u', \
1508c2ecf20Sopenharmony_ci			.realbits = 32, \
1518c2ecf20Sopenharmony_ci			.storagebits = 32, \
1528c2ecf20Sopenharmony_ci			.endianness = IIO_BE, \
1538c2ecf20Sopenharmony_ci		}, \
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic const struct iio_chan_spec atlas_ec_channels[] = {
1578c2ecf20Sopenharmony_ci	{
1588c2ecf20Sopenharmony_ci		.type = IIO_ELECTRICALCONDUCTIVITY,
1598c2ecf20Sopenharmony_ci		.address = ATLAS_REG_EC_DATA,
1608c2ecf20Sopenharmony_ci		.info_mask_separate =
1618c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
1628c2ecf20Sopenharmony_ci		.scan_index = 0,
1638c2ecf20Sopenharmony_ci		.scan_type = {
1648c2ecf20Sopenharmony_ci			.sign = 'u',
1658c2ecf20Sopenharmony_ci			.realbits = 32,
1668c2ecf20Sopenharmony_ci			.storagebits = 32,
1678c2ecf20Sopenharmony_ci			.endianness = IIO_BE,
1688c2ecf20Sopenharmony_ci		},
1698c2ecf20Sopenharmony_ci	},
1708c2ecf20Sopenharmony_ci	ATLAS_CONCENTRATION_CHANNEL(0, ATLAS_REG_TDS_DATA),
1718c2ecf20Sopenharmony_ci	ATLAS_CONCENTRATION_CHANNEL(1, ATLAS_REG_PSS_DATA),
1728c2ecf20Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(3),
1738c2ecf20Sopenharmony_ci	{
1748c2ecf20Sopenharmony_ci		.type = IIO_TEMP,
1758c2ecf20Sopenharmony_ci		.address = ATLAS_REG_EC_TEMP_DATA,
1768c2ecf20Sopenharmony_ci		.info_mask_separate =
1778c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
1788c2ecf20Sopenharmony_ci		.output = 1,
1798c2ecf20Sopenharmony_ci		.scan_index = -1
1808c2ecf20Sopenharmony_ci	},
1818c2ecf20Sopenharmony_ci};
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic const struct iio_chan_spec atlas_orp_channels[] = {
1848c2ecf20Sopenharmony_ci	{
1858c2ecf20Sopenharmony_ci		.type = IIO_VOLTAGE,
1868c2ecf20Sopenharmony_ci		.address = ATLAS_REG_ORP_DATA,
1878c2ecf20Sopenharmony_ci		.info_mask_separate =
1888c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
1898c2ecf20Sopenharmony_ci		.scan_index = 0,
1908c2ecf20Sopenharmony_ci		.scan_type = {
1918c2ecf20Sopenharmony_ci			.sign = 's',
1928c2ecf20Sopenharmony_ci			.realbits = 32,
1938c2ecf20Sopenharmony_ci			.storagebits = 32,
1948c2ecf20Sopenharmony_ci			.endianness = IIO_BE,
1958c2ecf20Sopenharmony_ci		},
1968c2ecf20Sopenharmony_ci	},
1978c2ecf20Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(1),
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic const struct iio_chan_spec atlas_do_channels[] = {
2018c2ecf20Sopenharmony_ci	{
2028c2ecf20Sopenharmony_ci		.type = IIO_CONCENTRATION,
2038c2ecf20Sopenharmony_ci		.address = ATLAS_REG_DO_DATA,
2048c2ecf20Sopenharmony_ci		.info_mask_separate =
2058c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
2068c2ecf20Sopenharmony_ci		.scan_index = 0,
2078c2ecf20Sopenharmony_ci		.scan_type = {
2088c2ecf20Sopenharmony_ci			.sign = 'u',
2098c2ecf20Sopenharmony_ci			.realbits = 32,
2108c2ecf20Sopenharmony_ci			.storagebits = 32,
2118c2ecf20Sopenharmony_ci			.endianness = IIO_BE,
2128c2ecf20Sopenharmony_ci		},
2138c2ecf20Sopenharmony_ci	},
2148c2ecf20Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(1),
2158c2ecf20Sopenharmony_ci	{
2168c2ecf20Sopenharmony_ci		.type = IIO_TEMP,
2178c2ecf20Sopenharmony_ci		.address = ATLAS_REG_DO_TEMP_DATA,
2188c2ecf20Sopenharmony_ci		.info_mask_separate =
2198c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
2208c2ecf20Sopenharmony_ci		.output = 1,
2218c2ecf20Sopenharmony_ci		.scan_index = -1
2228c2ecf20Sopenharmony_ci	},
2238c2ecf20Sopenharmony_ci};
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic const struct iio_chan_spec atlas_rtd_channels[] = {
2268c2ecf20Sopenharmony_ci	{
2278c2ecf20Sopenharmony_ci		.type = IIO_TEMP,
2288c2ecf20Sopenharmony_ci		.address = ATLAS_REG_RTD_DATA,
2298c2ecf20Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
2308c2ecf20Sopenharmony_ci		.scan_index = 0,
2318c2ecf20Sopenharmony_ci		.scan_type = {
2328c2ecf20Sopenharmony_ci			.sign = 's',
2338c2ecf20Sopenharmony_ci			.realbits = 32,
2348c2ecf20Sopenharmony_ci			.storagebits = 32,
2358c2ecf20Sopenharmony_ci			.endianness = IIO_BE,
2368c2ecf20Sopenharmony_ci		},
2378c2ecf20Sopenharmony_ci	},
2388c2ecf20Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(1),
2398c2ecf20Sopenharmony_ci};
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int atlas_check_ph_calibration(struct atlas_data *data)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct device *dev = &data->client->dev;
2448c2ecf20Sopenharmony_ci	int ret;
2458c2ecf20Sopenharmony_ci	unsigned int val;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	ret = regmap_read(data->regmap, ATLAS_REG_PH_CALIB_STATUS, &val);
2488c2ecf20Sopenharmony_ci	if (ret)
2498c2ecf20Sopenharmony_ci		return ret;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (!(val & ATLAS_REG_PH_CALIB_STATUS_MASK)) {
2528c2ecf20Sopenharmony_ci		dev_warn(dev, "device has not been calibrated\n");
2538c2ecf20Sopenharmony_ci		return 0;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (!(val & ATLAS_REG_PH_CALIB_STATUS_LOW))
2578c2ecf20Sopenharmony_ci		dev_warn(dev, "device missing low point calibration\n");
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (!(val & ATLAS_REG_PH_CALIB_STATUS_MID))
2608c2ecf20Sopenharmony_ci		dev_warn(dev, "device missing mid point calibration\n");
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (!(val & ATLAS_REG_PH_CALIB_STATUS_HIGH))
2638c2ecf20Sopenharmony_ci		dev_warn(dev, "device missing high point calibration\n");
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return 0;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic int atlas_check_ec_calibration(struct atlas_data *data)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct device *dev = &data->client->dev;
2718c2ecf20Sopenharmony_ci	int ret;
2728c2ecf20Sopenharmony_ci	unsigned int val;
2738c2ecf20Sopenharmony_ci	__be16	rval;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &rval, 2);
2768c2ecf20Sopenharmony_ci	if (ret)
2778c2ecf20Sopenharmony_ci		return ret;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	val = be16_to_cpu(rval);
2808c2ecf20Sopenharmony_ci	dev_info(dev, "probe set to K = %d.%.2d", val / 100, val % 100);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	ret = regmap_read(data->regmap, ATLAS_REG_EC_CALIB_STATUS, &val);
2838c2ecf20Sopenharmony_ci	if (ret)
2848c2ecf20Sopenharmony_ci		return ret;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (!(val & ATLAS_REG_EC_CALIB_STATUS_MASK)) {
2878c2ecf20Sopenharmony_ci		dev_warn(dev, "device has not been calibrated\n");
2888c2ecf20Sopenharmony_ci		return 0;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (!(val & ATLAS_REG_EC_CALIB_STATUS_DRY))
2928c2ecf20Sopenharmony_ci		dev_warn(dev, "device missing dry point calibration\n");
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (val & ATLAS_REG_EC_CALIB_STATUS_SINGLE) {
2958c2ecf20Sopenharmony_ci		dev_warn(dev, "device using single point calibration\n");
2968c2ecf20Sopenharmony_ci	} else {
2978c2ecf20Sopenharmony_ci		if (!(val & ATLAS_REG_EC_CALIB_STATUS_LOW))
2988c2ecf20Sopenharmony_ci			dev_warn(dev, "device missing low point calibration\n");
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		if (!(val & ATLAS_REG_EC_CALIB_STATUS_HIGH))
3018c2ecf20Sopenharmony_ci			dev_warn(dev, "device missing high point calibration\n");
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	return 0;
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic int atlas_check_orp_calibration(struct atlas_data *data)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct device *dev = &data->client->dev;
3108c2ecf20Sopenharmony_ci	int ret;
3118c2ecf20Sopenharmony_ci	unsigned int val;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	ret = regmap_read(data->regmap, ATLAS_REG_ORP_CALIB_STATUS, &val);
3148c2ecf20Sopenharmony_ci	if (ret)
3158c2ecf20Sopenharmony_ci		return ret;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (!val)
3188c2ecf20Sopenharmony_ci		dev_warn(dev, "device has not been calibrated\n");
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	return 0;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic int atlas_check_do_calibration(struct atlas_data *data)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	struct device *dev = &data->client->dev;
3268c2ecf20Sopenharmony_ci	int ret;
3278c2ecf20Sopenharmony_ci	unsigned int val;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	ret = regmap_read(data->regmap, ATLAS_REG_DO_CALIB_STATUS, &val);
3308c2ecf20Sopenharmony_ci	if (ret)
3318c2ecf20Sopenharmony_ci		return ret;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (!(val & ATLAS_REG_DO_CALIB_STATUS_MASK)) {
3348c2ecf20Sopenharmony_ci		dev_warn(dev, "device has not been calibrated\n");
3358c2ecf20Sopenharmony_ci		return 0;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (!(val & ATLAS_REG_DO_CALIB_STATUS_PRESSURE))
3398c2ecf20Sopenharmony_ci		dev_warn(dev, "device missing atmospheric pressure calibration\n");
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (!(val & ATLAS_REG_DO_CALIB_STATUS_DO))
3428c2ecf20Sopenharmony_ci		dev_warn(dev, "device missing dissolved oxygen calibration\n");
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	return 0;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistruct atlas_device {
3488c2ecf20Sopenharmony_ci	const struct iio_chan_spec *channels;
3498c2ecf20Sopenharmony_ci	int num_channels;
3508c2ecf20Sopenharmony_ci	int data_reg;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	int (*calibration)(struct atlas_data *data);
3538c2ecf20Sopenharmony_ci	int delay;
3548c2ecf20Sopenharmony_ci};
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic struct atlas_device atlas_devices[] = {
3578c2ecf20Sopenharmony_ci	[ATLAS_PH_SM] = {
3588c2ecf20Sopenharmony_ci				.channels = atlas_ph_channels,
3598c2ecf20Sopenharmony_ci				.num_channels = 3,
3608c2ecf20Sopenharmony_ci				.data_reg = ATLAS_REG_PH_DATA,
3618c2ecf20Sopenharmony_ci				.calibration = &atlas_check_ph_calibration,
3628c2ecf20Sopenharmony_ci				.delay = ATLAS_PH_INT_TIME_IN_MS,
3638c2ecf20Sopenharmony_ci	},
3648c2ecf20Sopenharmony_ci	[ATLAS_EC_SM] = {
3658c2ecf20Sopenharmony_ci				.channels = atlas_ec_channels,
3668c2ecf20Sopenharmony_ci				.num_channels = 5,
3678c2ecf20Sopenharmony_ci				.data_reg = ATLAS_REG_EC_DATA,
3688c2ecf20Sopenharmony_ci				.calibration = &atlas_check_ec_calibration,
3698c2ecf20Sopenharmony_ci				.delay = ATLAS_EC_INT_TIME_IN_MS,
3708c2ecf20Sopenharmony_ci	},
3718c2ecf20Sopenharmony_ci	[ATLAS_ORP_SM] = {
3728c2ecf20Sopenharmony_ci				.channels = atlas_orp_channels,
3738c2ecf20Sopenharmony_ci				.num_channels = 2,
3748c2ecf20Sopenharmony_ci				.data_reg = ATLAS_REG_ORP_DATA,
3758c2ecf20Sopenharmony_ci				.calibration = &atlas_check_orp_calibration,
3768c2ecf20Sopenharmony_ci				.delay = ATLAS_ORP_INT_TIME_IN_MS,
3778c2ecf20Sopenharmony_ci	},
3788c2ecf20Sopenharmony_ci	[ATLAS_DO_SM] = {
3798c2ecf20Sopenharmony_ci				.channels = atlas_do_channels,
3808c2ecf20Sopenharmony_ci				.num_channels = 3,
3818c2ecf20Sopenharmony_ci				.data_reg = ATLAS_REG_DO_DATA,
3828c2ecf20Sopenharmony_ci				.calibration = &atlas_check_do_calibration,
3838c2ecf20Sopenharmony_ci				.delay = ATLAS_DO_INT_TIME_IN_MS,
3848c2ecf20Sopenharmony_ci	},
3858c2ecf20Sopenharmony_ci	[ATLAS_RTD_SM] = {
3868c2ecf20Sopenharmony_ci				.channels = atlas_rtd_channels,
3878c2ecf20Sopenharmony_ci				.num_channels = 2,
3888c2ecf20Sopenharmony_ci				.data_reg = ATLAS_REG_RTD_DATA,
3898c2ecf20Sopenharmony_ci				.delay = ATLAS_RTD_INT_TIME_IN_MS,
3908c2ecf20Sopenharmony_ci	},
3918c2ecf20Sopenharmony_ci};
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int atlas_set_powermode(struct atlas_data *data, int on)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	return regmap_write(data->regmap, ATLAS_REG_PWR_CONTROL, on);
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistatic int atlas_set_interrupt(struct atlas_data *data, bool state)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	if (!data->interrupt_enabled)
4018c2ecf20Sopenharmony_ci		return 0;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	return regmap_update_bits(data->regmap, ATLAS_REG_INT_CONTROL,
4048c2ecf20Sopenharmony_ci				  ATLAS_REG_INT_CONTROL_EN,
4058c2ecf20Sopenharmony_ci				  state ? ATLAS_REG_INT_CONTROL_EN : 0);
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic int atlas_buffer_postenable(struct iio_dev *indio_dev)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct atlas_data *data = iio_priv(indio_dev);
4118c2ecf20Sopenharmony_ci	int ret;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(&data->client->dev);
4148c2ecf20Sopenharmony_ci	if (ret < 0) {
4158c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(&data->client->dev);
4168c2ecf20Sopenharmony_ci		return ret;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return atlas_set_interrupt(data, true);
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int atlas_buffer_predisable(struct iio_dev *indio_dev)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct atlas_data *data = iio_priv(indio_dev);
4258c2ecf20Sopenharmony_ci	int ret;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	ret = atlas_set_interrupt(data, false);
4288c2ecf20Sopenharmony_ci	if (ret)
4298c2ecf20Sopenharmony_ci		return ret;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(&data->client->dev);
4328c2ecf20Sopenharmony_ci	ret = pm_runtime_put_autosuspend(&data->client->dev);
4338c2ecf20Sopenharmony_ci	if (ret)
4348c2ecf20Sopenharmony_ci		return ret;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	return 0;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic const struct iio_trigger_ops atlas_interrupt_trigger_ops = {
4408c2ecf20Sopenharmony_ci};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic const struct iio_buffer_setup_ops atlas_buffer_setup_ops = {
4438c2ecf20Sopenharmony_ci	.postenable = atlas_buffer_postenable,
4448c2ecf20Sopenharmony_ci	.predisable = atlas_buffer_predisable,
4458c2ecf20Sopenharmony_ci};
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic void atlas_work_handler(struct irq_work *work)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct atlas_data *data = container_of(work, struct atlas_data, work);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	iio_trigger_poll(data->trig);
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic irqreturn_t atlas_trigger_handler(int irq, void *private)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct iio_poll_func *pf = private;
4578c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
4588c2ecf20Sopenharmony_ci	struct atlas_data *data = iio_priv(indio_dev);
4598c2ecf20Sopenharmony_ci	int channels = atlas_buffer_num_channels(data->chip->channels);
4608c2ecf20Sopenharmony_ci	int ret;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	ret = regmap_bulk_read(data->regmap, data->chip->data_reg,
4638c2ecf20Sopenharmony_ci			      &data->buffer, sizeof(__be32) * channels);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	if (!ret)
4668c2ecf20Sopenharmony_ci		iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
4678c2ecf20Sopenharmony_ci				iio_get_time_ns(indio_dev));
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic irqreturn_t atlas_interrupt_handler(int irq, void *private)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = private;
4778c2ecf20Sopenharmony_ci	struct atlas_data *data = iio_priv(indio_dev);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	irq_work_queue(&data->work);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	struct device *dev = &data->client->dev;
4878c2ecf20Sopenharmony_ci	int suspended = pm_runtime_suspended(dev);
4888c2ecf20Sopenharmony_ci	int ret;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(dev);
4918c2ecf20Sopenharmony_ci	if (ret < 0) {
4928c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(dev);
4938c2ecf20Sopenharmony_ci		return ret;
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (suspended)
4978c2ecf20Sopenharmony_ci		msleep(data->chip->delay);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	ret = regmap_bulk_read(data->regmap, reg, val, sizeof(*val));
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
5028c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(dev);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	return ret;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic int atlas_read_raw(struct iio_dev *indio_dev,
5088c2ecf20Sopenharmony_ci			  struct iio_chan_spec const *chan,
5098c2ecf20Sopenharmony_ci			  int *val, int *val2, long mask)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	struct atlas_data *data = iio_priv(indio_dev);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	switch (mask) {
5148c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
5158c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_RAW: {
5168c2ecf20Sopenharmony_ci		int ret;
5178c2ecf20Sopenharmony_ci		__be32 reg;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		switch (chan->type) {
5208c2ecf20Sopenharmony_ci		case IIO_TEMP:
5218c2ecf20Sopenharmony_ci			ret = regmap_bulk_read(data->regmap, chan->address,
5228c2ecf20Sopenharmony_ci					       &reg, sizeof(reg));
5238c2ecf20Sopenharmony_ci			break;
5248c2ecf20Sopenharmony_ci		case IIO_PH:
5258c2ecf20Sopenharmony_ci		case IIO_CONCENTRATION:
5268c2ecf20Sopenharmony_ci		case IIO_ELECTRICALCONDUCTIVITY:
5278c2ecf20Sopenharmony_ci		case IIO_VOLTAGE:
5288c2ecf20Sopenharmony_ci			ret = iio_device_claim_direct_mode(indio_dev);
5298c2ecf20Sopenharmony_ci			if (ret)
5308c2ecf20Sopenharmony_ci				return ret;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci			ret = atlas_read_measurement(data, chan->address, &reg);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci			iio_device_release_direct_mode(indio_dev);
5358c2ecf20Sopenharmony_ci			break;
5368c2ecf20Sopenharmony_ci		default:
5378c2ecf20Sopenharmony_ci			ret = -EINVAL;
5388c2ecf20Sopenharmony_ci		}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci		if (!ret) {
5418c2ecf20Sopenharmony_ci			*val = be32_to_cpu(reg);
5428c2ecf20Sopenharmony_ci			ret = IIO_VAL_INT;
5438c2ecf20Sopenharmony_ci		}
5448c2ecf20Sopenharmony_ci		return ret;
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
5478c2ecf20Sopenharmony_ci		switch (chan->type) {
5488c2ecf20Sopenharmony_ci		case IIO_TEMP:
5498c2ecf20Sopenharmony_ci			*val = 10;
5508c2ecf20Sopenharmony_ci			return IIO_VAL_INT;
5518c2ecf20Sopenharmony_ci		case IIO_PH:
5528c2ecf20Sopenharmony_ci			*val = 1; /* 0.001 */
5538c2ecf20Sopenharmony_ci			*val2 = 1000;
5548c2ecf20Sopenharmony_ci			break;
5558c2ecf20Sopenharmony_ci		case IIO_ELECTRICALCONDUCTIVITY:
5568c2ecf20Sopenharmony_ci			*val = 1; /* 0.00001 */
5578c2ecf20Sopenharmony_ci			*val2 = 100000;
5588c2ecf20Sopenharmony_ci			break;
5598c2ecf20Sopenharmony_ci		case IIO_CONCENTRATION:
5608c2ecf20Sopenharmony_ci			*val = 0; /* 0.000000001 */
5618c2ecf20Sopenharmony_ci			*val2 = 1000;
5628c2ecf20Sopenharmony_ci			return IIO_VAL_INT_PLUS_NANO;
5638c2ecf20Sopenharmony_ci		case IIO_VOLTAGE:
5648c2ecf20Sopenharmony_ci			*val = 1; /* 0.1 */
5658c2ecf20Sopenharmony_ci			*val2 = 10;
5668c2ecf20Sopenharmony_ci			break;
5678c2ecf20Sopenharmony_ci		default:
5688c2ecf20Sopenharmony_ci			return -EINVAL;
5698c2ecf20Sopenharmony_ci		}
5708c2ecf20Sopenharmony_ci		return IIO_VAL_FRACTIONAL;
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	return -EINVAL;
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_cistatic int atlas_write_raw(struct iio_dev *indio_dev,
5778c2ecf20Sopenharmony_ci			   struct iio_chan_spec const *chan,
5788c2ecf20Sopenharmony_ci			   int val, int val2, long mask)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct atlas_data *data = iio_priv(indio_dev);
5818c2ecf20Sopenharmony_ci	__be32 reg = cpu_to_be32(val / 10);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	if (val2 != 0 || val < 0 || val > 20000)
5848c2ecf20Sopenharmony_ci		return -EINVAL;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_TEMP)
5878c2ecf20Sopenharmony_ci		return -EINVAL;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	return regmap_bulk_write(data->regmap, chan->address,
5908c2ecf20Sopenharmony_ci				 &reg, sizeof(reg));
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic const struct iio_info atlas_info = {
5948c2ecf20Sopenharmony_ci	.read_raw = atlas_read_raw,
5958c2ecf20Sopenharmony_ci	.write_raw = atlas_write_raw,
5968c2ecf20Sopenharmony_ci};
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_cistatic const struct i2c_device_id atlas_id[] = {
5998c2ecf20Sopenharmony_ci	{ "atlas-ph-sm", ATLAS_PH_SM},
6008c2ecf20Sopenharmony_ci	{ "atlas-ec-sm", ATLAS_EC_SM},
6018c2ecf20Sopenharmony_ci	{ "atlas-orp-sm", ATLAS_ORP_SM},
6028c2ecf20Sopenharmony_ci	{ "atlas-do-sm", ATLAS_DO_SM},
6038c2ecf20Sopenharmony_ci	{ "atlas-rtd-sm", ATLAS_RTD_SM},
6048c2ecf20Sopenharmony_ci	{}
6058c2ecf20Sopenharmony_ci};
6068c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, atlas_id);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic const struct of_device_id atlas_dt_ids[] = {
6098c2ecf20Sopenharmony_ci	{ .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
6108c2ecf20Sopenharmony_ci	{ .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
6118c2ecf20Sopenharmony_ci	{ .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, },
6128c2ecf20Sopenharmony_ci	{ .compatible = "atlas,do-sm", .data = (void *)ATLAS_DO_SM, },
6138c2ecf20Sopenharmony_ci	{ .compatible = "atlas,rtd-sm", .data = (void *)ATLAS_RTD_SM, },
6148c2ecf20Sopenharmony_ci	{ }
6158c2ecf20Sopenharmony_ci};
6168c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, atlas_dt_ids);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic int atlas_probe(struct i2c_client *client,
6198c2ecf20Sopenharmony_ci		       const struct i2c_device_id *id)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct atlas_data *data;
6228c2ecf20Sopenharmony_ci	struct atlas_device *chip;
6238c2ecf20Sopenharmony_ci	struct iio_trigger *trig;
6248c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev;
6258c2ecf20Sopenharmony_ci	int ret;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
6288c2ecf20Sopenharmony_ci	if (!indio_dev)
6298c2ecf20Sopenharmony_ci		return -ENOMEM;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (!dev_fwnode(&client->dev))
6328c2ecf20Sopenharmony_ci		chip = &atlas_devices[id->driver_data];
6338c2ecf20Sopenharmony_ci	else
6348c2ecf20Sopenharmony_ci		chip = &atlas_devices[(unsigned long)device_get_match_data(&client->dev)];
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	indio_dev->info = &atlas_info;
6378c2ecf20Sopenharmony_ci	indio_dev->name = ATLAS_DRV_NAME;
6388c2ecf20Sopenharmony_ci	indio_dev->channels = chip->channels;
6398c2ecf20Sopenharmony_ci	indio_dev->num_channels = chip->num_channels;
6408c2ecf20Sopenharmony_ci	indio_dev->modes = INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
6438c2ecf20Sopenharmony_ci				      indio_dev->name, indio_dev->id);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	if (!trig)
6468c2ecf20Sopenharmony_ci		return -ENOMEM;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	data = iio_priv(indio_dev);
6498c2ecf20Sopenharmony_ci	data->client = client;
6508c2ecf20Sopenharmony_ci	data->trig = trig;
6518c2ecf20Sopenharmony_ci	data->chip = chip;
6528c2ecf20Sopenharmony_ci	trig->dev.parent = indio_dev->dev.parent;
6538c2ecf20Sopenharmony_ci	trig->ops = &atlas_interrupt_trigger_ops;
6548c2ecf20Sopenharmony_ci	iio_trigger_set_drvdata(trig, indio_dev);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, indio_dev);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	data->regmap = devm_regmap_init_i2c(client, &atlas_regmap_config);
6598c2ecf20Sopenharmony_ci	if (IS_ERR(data->regmap)) {
6608c2ecf20Sopenharmony_ci		dev_err(&client->dev, "regmap initialization failed\n");
6618c2ecf20Sopenharmony_ci		return PTR_ERR(data->regmap);
6628c2ecf20Sopenharmony_ci	}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	ret = pm_runtime_set_active(&client->dev);
6658c2ecf20Sopenharmony_ci	if (ret)
6668c2ecf20Sopenharmony_ci		return ret;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	ret = chip->calibration(data);
6698c2ecf20Sopenharmony_ci	if (ret)
6708c2ecf20Sopenharmony_ci		return ret;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	ret = iio_trigger_register(trig);
6738c2ecf20Sopenharmony_ci	if (ret) {
6748c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed to register trigger\n");
6758c2ecf20Sopenharmony_ci		return ret;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
6798c2ecf20Sopenharmony_ci		&atlas_trigger_handler, &atlas_buffer_setup_ops);
6808c2ecf20Sopenharmony_ci	if (ret) {
6818c2ecf20Sopenharmony_ci		dev_err(&client->dev, "cannot setup iio trigger\n");
6828c2ecf20Sopenharmony_ci		goto unregister_trigger;
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	init_irq_work(&data->work, atlas_work_handler);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (client->irq > 0) {
6888c2ecf20Sopenharmony_ci		/* interrupt pin toggles on new conversion */
6898c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(&client->dev, client->irq,
6908c2ecf20Sopenharmony_ci				NULL, atlas_interrupt_handler,
6918c2ecf20Sopenharmony_ci				IRQF_TRIGGER_RISING |
6928c2ecf20Sopenharmony_ci				IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
6938c2ecf20Sopenharmony_ci				"atlas_irq",
6948c2ecf20Sopenharmony_ci				indio_dev);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		if (ret)
6978c2ecf20Sopenharmony_ci			dev_warn(&client->dev,
6988c2ecf20Sopenharmony_ci				"request irq (%d) failed\n", client->irq);
6998c2ecf20Sopenharmony_ci		else
7008c2ecf20Sopenharmony_ci			data->interrupt_enabled = 1;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	ret = atlas_set_powermode(data, 1);
7048c2ecf20Sopenharmony_ci	if (ret) {
7058c2ecf20Sopenharmony_ci		dev_err(&client->dev, "cannot power device on");
7068c2ecf20Sopenharmony_ci		goto unregister_buffer;
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	pm_runtime_enable(&client->dev);
7108c2ecf20Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&client->dev, 2500);
7118c2ecf20Sopenharmony_ci	pm_runtime_use_autosuspend(&client->dev);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	ret = iio_device_register(indio_dev);
7148c2ecf20Sopenharmony_ci	if (ret) {
7158c2ecf20Sopenharmony_ci		dev_err(&client->dev, "unable to register device\n");
7168c2ecf20Sopenharmony_ci		goto unregister_pm;
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	return 0;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ciunregister_pm:
7228c2ecf20Sopenharmony_ci	pm_runtime_disable(&client->dev);
7238c2ecf20Sopenharmony_ci	atlas_set_powermode(data, 0);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ciunregister_buffer:
7268c2ecf20Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ciunregister_trigger:
7298c2ecf20Sopenharmony_ci	iio_trigger_unregister(data->trig);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	return ret;
7328c2ecf20Sopenharmony_ci}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_cistatic int atlas_remove(struct i2c_client *client)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(client);
7378c2ecf20Sopenharmony_ci	struct atlas_data *data = iio_priv(indio_dev);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	iio_device_unregister(indio_dev);
7408c2ecf20Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
7418c2ecf20Sopenharmony_ci	iio_trigger_unregister(data->trig);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	pm_runtime_disable(&client->dev);
7448c2ecf20Sopenharmony_ci	pm_runtime_set_suspended(&client->dev);
7458c2ecf20Sopenharmony_ci	pm_runtime_put_noidle(&client->dev);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	return atlas_set_powermode(data, 0);
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
7518c2ecf20Sopenharmony_cistatic int atlas_runtime_suspend(struct device *dev)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	struct atlas_data *data =
7548c2ecf20Sopenharmony_ci		     iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	return atlas_set_powermode(data, 0);
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic int atlas_runtime_resume(struct device *dev)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	struct atlas_data *data =
7628c2ecf20Sopenharmony_ci		     iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	return atlas_set_powermode(data, 1);
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci#endif
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_cistatic const struct dev_pm_ops atlas_pm_ops = {
7698c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(atlas_runtime_suspend,
7708c2ecf20Sopenharmony_ci			   atlas_runtime_resume, NULL)
7718c2ecf20Sopenharmony_ci};
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_cistatic struct i2c_driver atlas_driver = {
7748c2ecf20Sopenharmony_ci	.driver = {
7758c2ecf20Sopenharmony_ci		.name	= ATLAS_DRV_NAME,
7768c2ecf20Sopenharmony_ci		.of_match_table	= atlas_dt_ids,
7778c2ecf20Sopenharmony_ci		.pm	= &atlas_pm_ops,
7788c2ecf20Sopenharmony_ci	},
7798c2ecf20Sopenharmony_ci	.probe		= atlas_probe,
7808c2ecf20Sopenharmony_ci	.remove		= atlas_remove,
7818c2ecf20Sopenharmony_ci	.id_table	= atlas_id,
7828c2ecf20Sopenharmony_ci};
7838c2ecf20Sopenharmony_cimodule_i2c_driver(atlas_driver);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ciMODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
7868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Atlas Scientific SM sensors");
7878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
788