162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2020 InvenSense, Inc.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Driver for InvenSense ICP-1010xx barometric pressure and temperature sensor.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Datasheet:
862306a36Sopenharmony_ci * http://www.invensense.com/wp-content/uploads/2018/01/DS-000186-ICP-101xx-v1.2.pdf
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1462306a36Sopenharmony_ci#include <linux/i2c.h>
1562306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1662306a36Sopenharmony_ci#include <linux/crc8.h>
1762306a36Sopenharmony_ci#include <linux/mutex.h>
1862306a36Sopenharmony_ci#include <linux/delay.h>
1962306a36Sopenharmony_ci#include <linux/log2.h>
2062306a36Sopenharmony_ci#include <linux/math64.h>
2162306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2262306a36Sopenharmony_ci#include <linux/iio/iio.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define ICP10100_ID_REG_GET(_reg)	((_reg) & 0x003F)
2562306a36Sopenharmony_ci#define ICP10100_ID_REG			0x08
2662306a36Sopenharmony_ci#define ICP10100_RESPONSE_WORD_LENGTH	3
2762306a36Sopenharmony_ci#define ICP10100_CRC8_WORD_LENGTH	2
2862306a36Sopenharmony_ci#define ICP10100_CRC8_POLYNOMIAL	0x31
2962306a36Sopenharmony_ci#define ICP10100_CRC8_INIT		0xFF
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cienum icp10100_mode {
3262306a36Sopenharmony_ci	ICP10100_MODE_LP,	/* Low power mode: 1x sampling */
3362306a36Sopenharmony_ci	ICP10100_MODE_N,	/* Normal mode: 2x sampling */
3462306a36Sopenharmony_ci	ICP10100_MODE_LN,	/* Low noise mode: 4x sampling */
3562306a36Sopenharmony_ci	ICP10100_MODE_ULN,	/* Ultra low noise mode: 8x sampling */
3662306a36Sopenharmony_ci	ICP10100_MODE_NB,
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct icp10100_state {
4062306a36Sopenharmony_ci	struct mutex lock;
4162306a36Sopenharmony_ci	struct i2c_client *client;
4262306a36Sopenharmony_ci	struct regulator *vdd;
4362306a36Sopenharmony_ci	enum icp10100_mode mode;
4462306a36Sopenharmony_ci	int16_t cal[4];
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct icp10100_command {
4862306a36Sopenharmony_ci	__be16 cmd;
4962306a36Sopenharmony_ci	unsigned long wait_us;
5062306a36Sopenharmony_ci	unsigned long wait_max_us;
5162306a36Sopenharmony_ci	size_t response_word_nb;
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic const struct icp10100_command icp10100_cmd_soft_reset = {
5562306a36Sopenharmony_ci	.cmd = cpu_to_be16(0x805D),
5662306a36Sopenharmony_ci	.wait_us = 170,
5762306a36Sopenharmony_ci	.wait_max_us = 200,
5862306a36Sopenharmony_ci	.response_word_nb = 0,
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic const struct icp10100_command icp10100_cmd_read_id = {
6262306a36Sopenharmony_ci	.cmd = cpu_to_be16(0xEFC8),
6362306a36Sopenharmony_ci	.wait_us = 0,
6462306a36Sopenharmony_ci	.response_word_nb = 1,
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic const struct icp10100_command icp10100_cmd_read_otp = {
6862306a36Sopenharmony_ci	.cmd = cpu_to_be16(0xC7F7),
6962306a36Sopenharmony_ci	.wait_us = 0,
7062306a36Sopenharmony_ci	.response_word_nb = 1,
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic const struct icp10100_command icp10100_cmd_measure[] = {
7462306a36Sopenharmony_ci	[ICP10100_MODE_LP] = {
7562306a36Sopenharmony_ci		.cmd = cpu_to_be16(0x401A),
7662306a36Sopenharmony_ci		.wait_us = 1800,
7762306a36Sopenharmony_ci		.wait_max_us = 2000,
7862306a36Sopenharmony_ci		.response_word_nb = 3,
7962306a36Sopenharmony_ci	},
8062306a36Sopenharmony_ci	[ICP10100_MODE_N] = {
8162306a36Sopenharmony_ci		.cmd = cpu_to_be16(0x48A3),
8262306a36Sopenharmony_ci		.wait_us = 6300,
8362306a36Sopenharmony_ci		.wait_max_us = 6500,
8462306a36Sopenharmony_ci		.response_word_nb = 3,
8562306a36Sopenharmony_ci	},
8662306a36Sopenharmony_ci	[ICP10100_MODE_LN] = {
8762306a36Sopenharmony_ci		.cmd = cpu_to_be16(0x5059),
8862306a36Sopenharmony_ci		.wait_us = 23800,
8962306a36Sopenharmony_ci		.wait_max_us = 24000,
9062306a36Sopenharmony_ci		.response_word_nb = 3,
9162306a36Sopenharmony_ci	},
9262306a36Sopenharmony_ci	[ICP10100_MODE_ULN] = {
9362306a36Sopenharmony_ci		.cmd = cpu_to_be16(0x58E0),
9462306a36Sopenharmony_ci		.wait_us = 94500,
9562306a36Sopenharmony_ci		.wait_max_us = 94700,
9662306a36Sopenharmony_ci		.response_word_nb = 3,
9762306a36Sopenharmony_ci	},
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic const uint8_t icp10100_switch_mode_otp[] =
10162306a36Sopenharmony_ci	{0xC5, 0x95, 0x00, 0x66, 0x9c};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciDECLARE_CRC8_TABLE(icp10100_crc8_table);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic inline int icp10100_i2c_xfer(struct i2c_adapter *adap,
10662306a36Sopenharmony_ci				    struct i2c_msg *msgs, int num)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	int ret;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	ret = i2c_transfer(adap, msgs, num);
11162306a36Sopenharmony_ci	if (ret < 0)
11262306a36Sopenharmony_ci		return ret;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (ret != num)
11562306a36Sopenharmony_ci		return -EIO;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return 0;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int icp10100_send_cmd(struct icp10100_state *st,
12162306a36Sopenharmony_ci			     const struct icp10100_command *cmd,
12262306a36Sopenharmony_ci			     __be16 *buf, size_t buf_len)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	size_t size = cmd->response_word_nb * ICP10100_RESPONSE_WORD_LENGTH;
12562306a36Sopenharmony_ci	uint8_t data[16];
12662306a36Sopenharmony_ci	uint8_t *ptr;
12762306a36Sopenharmony_ci	uint8_t *buf_ptr = (uint8_t *)buf;
12862306a36Sopenharmony_ci	struct i2c_msg msgs[2] = {
12962306a36Sopenharmony_ci		{
13062306a36Sopenharmony_ci			.addr = st->client->addr,
13162306a36Sopenharmony_ci			.flags = 0,
13262306a36Sopenharmony_ci			.len = 2,
13362306a36Sopenharmony_ci			.buf = (uint8_t *)&cmd->cmd,
13462306a36Sopenharmony_ci		}, {
13562306a36Sopenharmony_ci			.addr = st->client->addr,
13662306a36Sopenharmony_ci			.flags = I2C_M_RD,
13762306a36Sopenharmony_ci			.len = size,
13862306a36Sopenharmony_ci			.buf = data,
13962306a36Sopenharmony_ci		},
14062306a36Sopenharmony_ci	};
14162306a36Sopenharmony_ci	uint8_t crc;
14262306a36Sopenharmony_ci	unsigned int i;
14362306a36Sopenharmony_ci	int ret;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (size > sizeof(data))
14662306a36Sopenharmony_ci		return -EINVAL;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (cmd->response_word_nb > 0 &&
14962306a36Sopenharmony_ci			(buf == NULL || buf_len < (cmd->response_word_nb * 2)))
15062306a36Sopenharmony_ci		return -EINVAL;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	dev_dbg(&st->client->dev, "sending cmd %#x\n", be16_to_cpu(cmd->cmd));
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (cmd->response_word_nb > 0 && cmd->wait_us == 0) {
15562306a36Sopenharmony_ci		/* direct command-response without waiting */
15662306a36Sopenharmony_ci		ret = icp10100_i2c_xfer(st->client->adapter, msgs,
15762306a36Sopenharmony_ci					ARRAY_SIZE(msgs));
15862306a36Sopenharmony_ci		if (ret)
15962306a36Sopenharmony_ci			return ret;
16062306a36Sopenharmony_ci	} else {
16162306a36Sopenharmony_ci		/* transfer command write */
16262306a36Sopenharmony_ci		ret = icp10100_i2c_xfer(st->client->adapter, &msgs[0], 1);
16362306a36Sopenharmony_ci		if (ret)
16462306a36Sopenharmony_ci			return ret;
16562306a36Sopenharmony_ci		if (cmd->wait_us > 0)
16662306a36Sopenharmony_ci			usleep_range(cmd->wait_us, cmd->wait_max_us);
16762306a36Sopenharmony_ci		/* transfer response read if needed */
16862306a36Sopenharmony_ci		if (cmd->response_word_nb > 0) {
16962306a36Sopenharmony_ci			ret = icp10100_i2c_xfer(st->client->adapter, &msgs[1], 1);
17062306a36Sopenharmony_ci			if (ret)
17162306a36Sopenharmony_ci				return ret;
17262306a36Sopenharmony_ci		} else {
17362306a36Sopenharmony_ci			return 0;
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* process read words with crc checking */
17862306a36Sopenharmony_ci	for (i = 0; i < cmd->response_word_nb; ++i) {
17962306a36Sopenharmony_ci		ptr = &data[i * ICP10100_RESPONSE_WORD_LENGTH];
18062306a36Sopenharmony_ci		crc = crc8(icp10100_crc8_table, ptr, ICP10100_CRC8_WORD_LENGTH,
18162306a36Sopenharmony_ci			   ICP10100_CRC8_INIT);
18262306a36Sopenharmony_ci		if (crc != ptr[ICP10100_CRC8_WORD_LENGTH]) {
18362306a36Sopenharmony_ci			dev_err(&st->client->dev, "crc error recv=%#x calc=%#x\n",
18462306a36Sopenharmony_ci				ptr[ICP10100_CRC8_WORD_LENGTH], crc);
18562306a36Sopenharmony_ci			return -EIO;
18662306a36Sopenharmony_ci		}
18762306a36Sopenharmony_ci		*buf_ptr++ = ptr[0];
18862306a36Sopenharmony_ci		*buf_ptr++ = ptr[1];
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return 0;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic int icp10100_read_cal_otp(struct icp10100_state *st)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	__be16 val;
19762306a36Sopenharmony_ci	int i;
19862306a36Sopenharmony_ci	int ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/* switch into OTP read mode */
20162306a36Sopenharmony_ci	ret = i2c_master_send(st->client, icp10100_switch_mode_otp,
20262306a36Sopenharmony_ci			      ARRAY_SIZE(icp10100_switch_mode_otp));
20362306a36Sopenharmony_ci	if (ret < 0)
20462306a36Sopenharmony_ci		return ret;
20562306a36Sopenharmony_ci	if (ret != ARRAY_SIZE(icp10100_switch_mode_otp))
20662306a36Sopenharmony_ci		return -EIO;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* read 4 calibration values */
20962306a36Sopenharmony_ci	for (i = 0; i < 4; ++i) {
21062306a36Sopenharmony_ci		ret = icp10100_send_cmd(st, &icp10100_cmd_read_otp,
21162306a36Sopenharmony_ci					&val, sizeof(val));
21262306a36Sopenharmony_ci		if (ret)
21362306a36Sopenharmony_ci			return ret;
21462306a36Sopenharmony_ci		st->cal[i] = be16_to_cpu(val);
21562306a36Sopenharmony_ci		dev_dbg(&st->client->dev, "cal[%d] = %d\n", i, st->cal[i]);
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int icp10100_init_chip(struct icp10100_state *st)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	__be16 val;
22462306a36Sopenharmony_ci	uint16_t id;
22562306a36Sopenharmony_ci	int ret;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/* read and check id */
22862306a36Sopenharmony_ci	ret = icp10100_send_cmd(st, &icp10100_cmd_read_id, &val, sizeof(val));
22962306a36Sopenharmony_ci	if (ret)
23062306a36Sopenharmony_ci		return ret;
23162306a36Sopenharmony_ci	id = ICP10100_ID_REG_GET(be16_to_cpu(val));
23262306a36Sopenharmony_ci	if (id != ICP10100_ID_REG) {
23362306a36Sopenharmony_ci		dev_err(&st->client->dev, "invalid id %#x\n", id);
23462306a36Sopenharmony_ci		return -ENODEV;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* read calibration data from OTP */
23862306a36Sopenharmony_ci	ret = icp10100_read_cal_otp(st);
23962306a36Sopenharmony_ci	if (ret)
24062306a36Sopenharmony_ci		return ret;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/* reset chip */
24362306a36Sopenharmony_ci	return icp10100_send_cmd(st, &icp10100_cmd_soft_reset, NULL, 0);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic int icp10100_get_measures(struct icp10100_state *st,
24762306a36Sopenharmony_ci				uint32_t *pressure, uint16_t *temperature)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	const struct icp10100_command *cmd;
25062306a36Sopenharmony_ci	__be16 measures[3];
25162306a36Sopenharmony_ci	int ret;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(&st->client->dev);
25462306a36Sopenharmony_ci	if (ret < 0)
25562306a36Sopenharmony_ci		return ret;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	mutex_lock(&st->lock);
25862306a36Sopenharmony_ci	cmd = &icp10100_cmd_measure[st->mode];
25962306a36Sopenharmony_ci	ret = icp10100_send_cmd(st, cmd, measures, sizeof(measures));
26062306a36Sopenharmony_ci	mutex_unlock(&st->lock);
26162306a36Sopenharmony_ci	if (ret)
26262306a36Sopenharmony_ci		goto error_measure;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	*pressure = (be16_to_cpu(measures[0]) << 8) |
26562306a36Sopenharmony_ci			(be16_to_cpu(measures[1]) >> 8);
26662306a36Sopenharmony_ci	*temperature = be16_to_cpu(measures[2]);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&st->client->dev);
26962306a36Sopenharmony_cierror_measure:
27062306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&st->client->dev);
27162306a36Sopenharmony_ci	return ret;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic uint32_t icp10100_get_pressure(struct icp10100_state *st,
27562306a36Sopenharmony_ci				      uint32_t raw_pressure, uint16_t raw_temp)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	static int32_t p_calib[] = {45000, 80000, 105000};
27862306a36Sopenharmony_ci	static int32_t lut_lower = 3670016;
27962306a36Sopenharmony_ci	static int32_t lut_upper = 12058624;
28062306a36Sopenharmony_ci	static int32_t inv_quadr_factor = 16777216;
28162306a36Sopenharmony_ci	static int32_t offset_factor = 2048;
28262306a36Sopenharmony_ci	int64_t val1, val2;
28362306a36Sopenharmony_ci	int32_t p_lut[3];
28462306a36Sopenharmony_ci	int32_t t, t_square;
28562306a36Sopenharmony_ci	int64_t a, b, c;
28662306a36Sopenharmony_ci	uint32_t pressure_mPa;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	dev_dbg(&st->client->dev, "raw: pressure = %u, temp = %u\n",
28962306a36Sopenharmony_ci		raw_pressure, raw_temp);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* compute p_lut values */
29262306a36Sopenharmony_ci	t = (int32_t)raw_temp - 32768;
29362306a36Sopenharmony_ci	t_square = t * t;
29462306a36Sopenharmony_ci	val1 = (int64_t)st->cal[0] * (int64_t)t_square;
29562306a36Sopenharmony_ci	p_lut[0] = lut_lower + (int32_t)div_s64(val1, inv_quadr_factor);
29662306a36Sopenharmony_ci	val1 = (int64_t)st->cal[1] * (int64_t)t_square;
29762306a36Sopenharmony_ci	p_lut[1] = offset_factor * st->cal[3] +
29862306a36Sopenharmony_ci			(int32_t)div_s64(val1, inv_quadr_factor);
29962306a36Sopenharmony_ci	val1 = (int64_t)st->cal[2] * (int64_t)t_square;
30062306a36Sopenharmony_ci	p_lut[2] = lut_upper + (int32_t)div_s64(val1, inv_quadr_factor);
30162306a36Sopenharmony_ci	dev_dbg(&st->client->dev, "p_lut = [%d, %d, %d]\n",
30262306a36Sopenharmony_ci		p_lut[0], p_lut[1], p_lut[2]);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/* compute a, b, c factors */
30562306a36Sopenharmony_ci	val1 = (int64_t)p_lut[0] * (int64_t)p_lut[1] *
30662306a36Sopenharmony_ci			(int64_t)(p_calib[0] - p_calib[1]) +
30762306a36Sopenharmony_ci		(int64_t)p_lut[1] * (int64_t)p_lut[2] *
30862306a36Sopenharmony_ci			(int64_t)(p_calib[1] - p_calib[2]) +
30962306a36Sopenharmony_ci		(int64_t)p_lut[2] * (int64_t)p_lut[0] *
31062306a36Sopenharmony_ci			(int64_t)(p_calib[2] - p_calib[0]);
31162306a36Sopenharmony_ci	val2 = (int64_t)p_lut[2] * (int64_t)(p_calib[0] - p_calib[1]) +
31262306a36Sopenharmony_ci		(int64_t)p_lut[0] * (int64_t)(p_calib[1] - p_calib[2]) +
31362306a36Sopenharmony_ci		(int64_t)p_lut[1] * (int64_t)(p_calib[2] - p_calib[0]);
31462306a36Sopenharmony_ci	c = div64_s64(val1, val2);
31562306a36Sopenharmony_ci	dev_dbg(&st->client->dev, "val1 = %lld, val2 = %lld, c = %lld\n",
31662306a36Sopenharmony_ci		val1, val2, c);
31762306a36Sopenharmony_ci	val1 = (int64_t)p_calib[0] * (int64_t)p_lut[0] -
31862306a36Sopenharmony_ci		(int64_t)p_calib[1] * (int64_t)p_lut[1] -
31962306a36Sopenharmony_ci		(int64_t)(p_calib[1] - p_calib[0]) * c;
32062306a36Sopenharmony_ci	val2 = (int64_t)p_lut[0] - (int64_t)p_lut[1];
32162306a36Sopenharmony_ci	a = div64_s64(val1, val2);
32262306a36Sopenharmony_ci	dev_dbg(&st->client->dev, "val1 = %lld, val2 = %lld, a = %lld\n",
32362306a36Sopenharmony_ci		val1, val2, a);
32462306a36Sopenharmony_ci	b = ((int64_t)p_calib[0] - a) * ((int64_t)p_lut[0] + c);
32562306a36Sopenharmony_ci	dev_dbg(&st->client->dev, "b = %lld\n", b);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/*
32862306a36Sopenharmony_ci	 * pressure_Pa = a + (b / (c + raw_pressure))
32962306a36Sopenharmony_ci	 * pressure_mPa = 1000 * pressure_Pa
33062306a36Sopenharmony_ci	 */
33162306a36Sopenharmony_ci	pressure_mPa = 1000LL * a + div64_s64(1000LL * b, c + raw_pressure);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return pressure_mPa;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int icp10100_read_raw_measures(struct iio_dev *indio_dev,
33762306a36Sopenharmony_ci				      struct iio_chan_spec const *chan,
33862306a36Sopenharmony_ci				      int *val, int *val2)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct icp10100_state *st = iio_priv(indio_dev);
34162306a36Sopenharmony_ci	uint32_t raw_pressure;
34262306a36Sopenharmony_ci	uint16_t raw_temp;
34362306a36Sopenharmony_ci	uint32_t pressure_mPa;
34462306a36Sopenharmony_ci	int ret;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	ret = iio_device_claim_direct_mode(indio_dev);
34762306a36Sopenharmony_ci	if (ret)
34862306a36Sopenharmony_ci		return ret;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	ret = icp10100_get_measures(st, &raw_pressure, &raw_temp);
35162306a36Sopenharmony_ci	if (ret)
35262306a36Sopenharmony_ci		goto error_release;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	switch (chan->type) {
35562306a36Sopenharmony_ci	case IIO_PRESSURE:
35662306a36Sopenharmony_ci		pressure_mPa = icp10100_get_pressure(st, raw_pressure,
35762306a36Sopenharmony_ci						     raw_temp);
35862306a36Sopenharmony_ci		/* mPa to kPa */
35962306a36Sopenharmony_ci		*val = pressure_mPa / 1000000;
36062306a36Sopenharmony_ci		*val2 = pressure_mPa % 1000000;
36162306a36Sopenharmony_ci		ret = IIO_VAL_INT_PLUS_MICRO;
36262306a36Sopenharmony_ci		break;
36362306a36Sopenharmony_ci	case IIO_TEMP:
36462306a36Sopenharmony_ci		*val = raw_temp;
36562306a36Sopenharmony_ci		ret = IIO_VAL_INT;
36662306a36Sopenharmony_ci		break;
36762306a36Sopenharmony_ci	default:
36862306a36Sopenharmony_ci		ret = -EINVAL;
36962306a36Sopenharmony_ci		break;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cierror_release:
37362306a36Sopenharmony_ci	iio_device_release_direct_mode(indio_dev);
37462306a36Sopenharmony_ci	return ret;
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic int icp10100_read_raw(struct iio_dev *indio_dev,
37862306a36Sopenharmony_ci			     struct iio_chan_spec const *chan,
37962306a36Sopenharmony_ci			     int *val, int *val2, long mask)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct icp10100_state *st = iio_priv(indio_dev);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	switch (mask) {
38462306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
38562306a36Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
38662306a36Sopenharmony_ci		return icp10100_read_raw_measures(indio_dev, chan, val, val2);
38762306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
38862306a36Sopenharmony_ci		switch (chan->type) {
38962306a36Sopenharmony_ci		case IIO_TEMP:
39062306a36Sopenharmony_ci			/* 1000 * 175°C / 65536 in m°C */
39162306a36Sopenharmony_ci			*val = 2;
39262306a36Sopenharmony_ci			*val2 = 670288;
39362306a36Sopenharmony_ci			return IIO_VAL_INT_PLUS_MICRO;
39462306a36Sopenharmony_ci		default:
39562306a36Sopenharmony_ci			return -EINVAL;
39662306a36Sopenharmony_ci		}
39762306a36Sopenharmony_ci		break;
39862306a36Sopenharmony_ci	case IIO_CHAN_INFO_OFFSET:
39962306a36Sopenharmony_ci		switch (chan->type) {
40062306a36Sopenharmony_ci		case IIO_TEMP:
40162306a36Sopenharmony_ci			/* 1000 * -45°C in m°C */
40262306a36Sopenharmony_ci			*val = -45000;
40362306a36Sopenharmony_ci			return IIO_VAL_INT;
40462306a36Sopenharmony_ci		default:
40562306a36Sopenharmony_ci			return -EINVAL;
40662306a36Sopenharmony_ci		}
40762306a36Sopenharmony_ci		break;
40862306a36Sopenharmony_ci	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
40962306a36Sopenharmony_ci		mutex_lock(&st->lock);
41062306a36Sopenharmony_ci		*val = 1 << st->mode;
41162306a36Sopenharmony_ci		mutex_unlock(&st->lock);
41262306a36Sopenharmony_ci		return IIO_VAL_INT;
41362306a36Sopenharmony_ci	default:
41462306a36Sopenharmony_ci		return -EINVAL;
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic int icp10100_read_avail(struct iio_dev *indio_dev,
41962306a36Sopenharmony_ci			       struct iio_chan_spec const *chan,
42062306a36Sopenharmony_ci			       const int **vals, int *type, int *length,
42162306a36Sopenharmony_ci			       long mask)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	static int oversamplings[] = {1, 2, 4, 8};
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	switch (mask) {
42662306a36Sopenharmony_ci	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
42762306a36Sopenharmony_ci		*vals = oversamplings;
42862306a36Sopenharmony_ci		*type = IIO_VAL_INT;
42962306a36Sopenharmony_ci		*length = ARRAY_SIZE(oversamplings);
43062306a36Sopenharmony_ci		return IIO_AVAIL_LIST;
43162306a36Sopenharmony_ci	default:
43262306a36Sopenharmony_ci		return -EINVAL;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int icp10100_write_raw(struct iio_dev *indio_dev,
43762306a36Sopenharmony_ci			      struct iio_chan_spec const *chan,
43862306a36Sopenharmony_ci			      int val, int val2, long mask)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct icp10100_state *st = iio_priv(indio_dev);
44162306a36Sopenharmony_ci	unsigned int mode;
44262306a36Sopenharmony_ci	int ret;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	switch (mask) {
44562306a36Sopenharmony_ci	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
44662306a36Sopenharmony_ci		/* oversampling is always positive and a power of 2 */
44762306a36Sopenharmony_ci		if (val <= 0 || !is_power_of_2(val))
44862306a36Sopenharmony_ci			return -EINVAL;
44962306a36Sopenharmony_ci		mode = ilog2(val);
45062306a36Sopenharmony_ci		if (mode >= ICP10100_MODE_NB)
45162306a36Sopenharmony_ci			return -EINVAL;
45262306a36Sopenharmony_ci		ret = iio_device_claim_direct_mode(indio_dev);
45362306a36Sopenharmony_ci		if (ret)
45462306a36Sopenharmony_ci			return ret;
45562306a36Sopenharmony_ci		mutex_lock(&st->lock);
45662306a36Sopenharmony_ci		st->mode = mode;
45762306a36Sopenharmony_ci		mutex_unlock(&st->lock);
45862306a36Sopenharmony_ci		iio_device_release_direct_mode(indio_dev);
45962306a36Sopenharmony_ci		return 0;
46062306a36Sopenharmony_ci	default:
46162306a36Sopenharmony_ci		return -EINVAL;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic int icp10100_write_raw_get_fmt(struct iio_dev *indio_dev,
46662306a36Sopenharmony_ci				      struct iio_chan_spec const *chan,
46762306a36Sopenharmony_ci				      long mask)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	switch (mask) {
47062306a36Sopenharmony_ci	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
47162306a36Sopenharmony_ci		return IIO_VAL_INT;
47262306a36Sopenharmony_ci	default:
47362306a36Sopenharmony_ci		return -EINVAL;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic const struct iio_info icp10100_info = {
47862306a36Sopenharmony_ci	.read_raw = icp10100_read_raw,
47962306a36Sopenharmony_ci	.read_avail = icp10100_read_avail,
48062306a36Sopenharmony_ci	.write_raw = icp10100_write_raw,
48162306a36Sopenharmony_ci	.write_raw_get_fmt = icp10100_write_raw_get_fmt,
48262306a36Sopenharmony_ci};
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic const struct iio_chan_spec icp10100_channels[] = {
48562306a36Sopenharmony_ci	{
48662306a36Sopenharmony_ci		.type = IIO_PRESSURE,
48762306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
48862306a36Sopenharmony_ci		.info_mask_shared_by_all =
48962306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
49062306a36Sopenharmony_ci		.info_mask_shared_by_all_available =
49162306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
49262306a36Sopenharmony_ci	}, {
49362306a36Sopenharmony_ci		.type = IIO_TEMP,
49462306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
49562306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE) |
49662306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_OFFSET),
49762306a36Sopenharmony_ci		.info_mask_shared_by_all =
49862306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
49962306a36Sopenharmony_ci		.info_mask_shared_by_all_available =
50062306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
50162306a36Sopenharmony_ci	},
50262306a36Sopenharmony_ci};
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic int icp10100_enable_regulator(struct icp10100_state *st)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	int ret;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	ret = regulator_enable(st->vdd);
50962306a36Sopenharmony_ci	if (ret)
51062306a36Sopenharmony_ci		return ret;
51162306a36Sopenharmony_ci	msleep(100);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	return 0;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic void icp10100_disable_regulator_action(void *data)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct icp10100_state *st = data;
51962306a36Sopenharmony_ci	int ret;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	ret = regulator_disable(st->vdd);
52262306a36Sopenharmony_ci	if (ret)
52362306a36Sopenharmony_ci		dev_err(&st->client->dev, "error %d disabling vdd\n", ret);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic void icp10100_pm_disable(void *data)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct device *dev = data;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	pm_runtime_disable(dev);
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic int icp10100_probe(struct i2c_client *client)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct iio_dev *indio_dev;
53662306a36Sopenharmony_ci	struct icp10100_state *st;
53762306a36Sopenharmony_ci	int ret;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
54062306a36Sopenharmony_ci		dev_err(&client->dev, "plain i2c transactions not supported\n");
54162306a36Sopenharmony_ci		return -ENODEV;
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
54562306a36Sopenharmony_ci	if (!indio_dev)
54662306a36Sopenharmony_ci		return -ENOMEM;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	i2c_set_clientdata(client, indio_dev);
54962306a36Sopenharmony_ci	indio_dev->name = client->name;
55062306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
55162306a36Sopenharmony_ci	indio_dev->channels = icp10100_channels;
55262306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(icp10100_channels);
55362306a36Sopenharmony_ci	indio_dev->info = &icp10100_info;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	st = iio_priv(indio_dev);
55662306a36Sopenharmony_ci	mutex_init(&st->lock);
55762306a36Sopenharmony_ci	st->client = client;
55862306a36Sopenharmony_ci	st->mode = ICP10100_MODE_N;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	st->vdd = devm_regulator_get(&client->dev, "vdd");
56162306a36Sopenharmony_ci	if (IS_ERR(st->vdd))
56262306a36Sopenharmony_ci		return PTR_ERR(st->vdd);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	ret = icp10100_enable_regulator(st);
56562306a36Sopenharmony_ci	if (ret)
56662306a36Sopenharmony_ci		return ret;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	ret = devm_add_action_or_reset(&client->dev,
56962306a36Sopenharmony_ci				       icp10100_disable_regulator_action, st);
57062306a36Sopenharmony_ci	if (ret)
57162306a36Sopenharmony_ci		return ret;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* has to be done before the first i2c communication */
57462306a36Sopenharmony_ci	crc8_populate_msb(icp10100_crc8_table, ICP10100_CRC8_POLYNOMIAL);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	ret = icp10100_init_chip(st);
57762306a36Sopenharmony_ci	if (ret) {
57862306a36Sopenharmony_ci		dev_err(&client->dev, "init chip error %d\n", ret);
57962306a36Sopenharmony_ci		return ret;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* enable runtime pm with autosuspend delay of 2s */
58362306a36Sopenharmony_ci	pm_runtime_get_noresume(&client->dev);
58462306a36Sopenharmony_ci	pm_runtime_set_active(&client->dev);
58562306a36Sopenharmony_ci	pm_runtime_enable(&client->dev);
58662306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&client->dev, 2000);
58762306a36Sopenharmony_ci	pm_runtime_use_autosuspend(&client->dev);
58862306a36Sopenharmony_ci	pm_runtime_put(&client->dev);
58962306a36Sopenharmony_ci	ret = devm_add_action_or_reset(&client->dev, icp10100_pm_disable,
59062306a36Sopenharmony_ci				       &client->dev);
59162306a36Sopenharmony_ci	if (ret)
59262306a36Sopenharmony_ci		return ret;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	return devm_iio_device_register(&client->dev, indio_dev);
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic int icp10100_suspend(struct device *dev)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	struct icp10100_state *st = iio_priv(dev_get_drvdata(dev));
60062306a36Sopenharmony_ci	int ret;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	mutex_lock(&st->lock);
60362306a36Sopenharmony_ci	ret = regulator_disable(st->vdd);
60462306a36Sopenharmony_ci	mutex_unlock(&st->lock);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return ret;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic int icp10100_resume(struct device *dev)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct icp10100_state *st = iio_priv(dev_get_drvdata(dev));
61262306a36Sopenharmony_ci	int ret;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	mutex_lock(&st->lock);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	ret = icp10100_enable_regulator(st);
61762306a36Sopenharmony_ci	if (ret)
61862306a36Sopenharmony_ci		goto out_unlock;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	/* reset chip */
62162306a36Sopenharmony_ci	ret = icp10100_send_cmd(st, &icp10100_cmd_soft_reset, NULL, 0);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ciout_unlock:
62462306a36Sopenharmony_ci	mutex_unlock(&st->lock);
62562306a36Sopenharmony_ci	return ret;
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic DEFINE_RUNTIME_DEV_PM_OPS(icp10100_pm, icp10100_suspend, icp10100_resume,
62962306a36Sopenharmony_ci				 NULL);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic const struct of_device_id icp10100_of_match[] = {
63262306a36Sopenharmony_ci	{
63362306a36Sopenharmony_ci		.compatible = "invensense,icp10100",
63462306a36Sopenharmony_ci	},
63562306a36Sopenharmony_ci	{ }
63662306a36Sopenharmony_ci};
63762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, icp10100_of_match);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic const struct i2c_device_id icp10100_id[] = {
64062306a36Sopenharmony_ci	{ "icp10100", 0 },
64162306a36Sopenharmony_ci	{ }
64262306a36Sopenharmony_ci};
64362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, icp10100_id);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic struct i2c_driver icp10100_driver = {
64662306a36Sopenharmony_ci	.driver = {
64762306a36Sopenharmony_ci		.name = "icp10100",
64862306a36Sopenharmony_ci		.pm = pm_ptr(&icp10100_pm),
64962306a36Sopenharmony_ci		.of_match_table = icp10100_of_match,
65062306a36Sopenharmony_ci	},
65162306a36Sopenharmony_ci	.probe = icp10100_probe,
65262306a36Sopenharmony_ci	.id_table = icp10100_id,
65362306a36Sopenharmony_ci};
65462306a36Sopenharmony_cimodule_i2c_driver(icp10100_driver);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ciMODULE_AUTHOR("InvenSense, Inc.");
65762306a36Sopenharmony_ciMODULE_DESCRIPTION("InvenSense icp10100 driver");
65862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
659