162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for the Yamaha YAS magnetic sensors, often used in Samsung
462306a36Sopenharmony_ci * mobile phones. While all are not yet handled because of lacking
562306a36Sopenharmony_ci * hardware, expand this driver to handle the different variants:
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * YAS530 MS-3E (2011 Samsung Galaxy S Advance)
862306a36Sopenharmony_ci * YAS532 MS-3R (2011 Samsung Galaxy S4)
962306a36Sopenharmony_ci * YAS533 MS-3F (Vivo 1633, 1707, V3, Y21L)
1062306a36Sopenharmony_ci * (YAS534 is a magnetic switch, not handled)
1162306a36Sopenharmony_ci * YAS535 MS-6C
1262306a36Sopenharmony_ci * YAS536 MS-3W
1362306a36Sopenharmony_ci * YAS537 MS-3T (2015 Samsung Galaxy S6, Note 5, Galaxy S7)
1462306a36Sopenharmony_ci * YAS539 MS-3S (2018 Samsung Galaxy A7 SM-A750FN)
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Code functions found in the MPU3050 YAS530 and YAS532 drivers
1762306a36Sopenharmony_ci * named "inv_compass" in the Tegra Android kernel tree.
1862306a36Sopenharmony_ci * Copyright (C) 2012 InvenSense Corporation
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Code functions for YAS537 based on Yamaha Android kernel driver.
2162306a36Sopenharmony_ci * Copyright (c) 2014 Yamaha Corporation
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Author: Linus Walleij <linus.walleij@linaro.org>
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_ci#include <linux/bitfield.h>
2662306a36Sopenharmony_ci#include <linux/bitops.h>
2762306a36Sopenharmony_ci#include <linux/delay.h>
2862306a36Sopenharmony_ci#include <linux/err.h>
2962306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
3062306a36Sopenharmony_ci#include <linux/i2c.h>
3162306a36Sopenharmony_ci#include <linux/module.h>
3262306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
3362306a36Sopenharmony_ci#include <linux/mutex.h>
3462306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3562306a36Sopenharmony_ci#include <linux/property.h>
3662306a36Sopenharmony_ci#include <linux/regmap.h>
3762306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
3862306a36Sopenharmony_ci#include <linux/random.h>
3962306a36Sopenharmony_ci#include <linux/units.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include <linux/iio/buffer.h>
4262306a36Sopenharmony_ci#include <linux/iio/iio.h>
4362306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
4462306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#include <asm/unaligned.h>
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Commonly used registers */
4962306a36Sopenharmony_ci#define YAS5XX_DEVICE_ID		0x80
5062306a36Sopenharmony_ci#define YAS5XX_MEASURE_DATA		0xB0
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* These registers are used by YAS530, YAS532 and YAS533 */
5362306a36Sopenharmony_ci#define YAS530_ACTUATE_INIT_COIL	0x81
5462306a36Sopenharmony_ci#define YAS530_MEASURE			0x82
5562306a36Sopenharmony_ci#define YAS530_CONFIG			0x83
5662306a36Sopenharmony_ci#define YAS530_MEASURE_INTERVAL		0x84
5762306a36Sopenharmony_ci#define YAS530_OFFSET_X			0x85 /* [-31 .. 31] */
5862306a36Sopenharmony_ci#define YAS530_OFFSET_Y1		0x86 /* [-31 .. 31] */
5962306a36Sopenharmony_ci#define YAS530_OFFSET_Y2		0x87 /* [-31 .. 31] */
6062306a36Sopenharmony_ci#define YAS530_TEST1			0x88
6162306a36Sopenharmony_ci#define YAS530_TEST2			0x89
6262306a36Sopenharmony_ci#define YAS530_CAL			0x90
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* Registers used by YAS537 */
6562306a36Sopenharmony_ci#define YAS537_MEASURE			0x81 /* Originally YAS537_REG_CMDR */
6662306a36Sopenharmony_ci#define YAS537_CONFIG			0x82 /* Originally YAS537_REG_CONFR */
6762306a36Sopenharmony_ci#define YAS537_MEASURE_INTERVAL		0x83 /* Originally YAS537_REG_INTRVLR */
6862306a36Sopenharmony_ci#define YAS537_OFFSET_X			0x84 /* Originally YAS537_REG_OXR */
6962306a36Sopenharmony_ci#define YAS537_OFFSET_Y1		0x85 /* Originally YAS537_REG_OY1R */
7062306a36Sopenharmony_ci#define YAS537_OFFSET_Y2		0x86 /* Originally YAS537_REG_OY2R */
7162306a36Sopenharmony_ci#define YAS537_AVR			0x87
7262306a36Sopenharmony_ci#define YAS537_HCK			0x88
7362306a36Sopenharmony_ci#define YAS537_LCK			0x89
7462306a36Sopenharmony_ci#define YAS537_SRST			0x90
7562306a36Sopenharmony_ci#define YAS537_ADCCAL			0x91
7662306a36Sopenharmony_ci#define YAS537_MTC			0x93
7762306a36Sopenharmony_ci#define YAS537_OC			0x9E
7862306a36Sopenharmony_ci#define YAS537_TRM			0x9F
7962306a36Sopenharmony_ci#define YAS537_CAL			0xC0
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* Bits in the YAS5xx config register */
8262306a36Sopenharmony_ci#define YAS5XX_CONFIG_INTON		BIT(0) /* Interrupt on? */
8362306a36Sopenharmony_ci#define YAS5XX_CONFIG_INTHACT		BIT(1) /* Interrupt active high? */
8462306a36Sopenharmony_ci#define YAS5XX_CONFIG_CCK_MASK		GENMASK(4, 2)
8562306a36Sopenharmony_ci#define YAS5XX_CONFIG_CCK_SHIFT		2
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* Bits in the measure command register */
8862306a36Sopenharmony_ci#define YAS5XX_MEASURE_START		BIT(0)
8962306a36Sopenharmony_ci#define YAS5XX_MEASURE_LDTC		BIT(1)
9062306a36Sopenharmony_ci#define YAS5XX_MEASURE_FORS		BIT(2)
9162306a36Sopenharmony_ci#define YAS5XX_MEASURE_DLYMES		BIT(4)
9262306a36Sopenharmony_ci#define YAS5XX_MEASURE_CONT		BIT(5)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/* Bits in the measure data register */
9562306a36Sopenharmony_ci#define YAS5XX_MEASURE_DATA_BUSY	BIT(7)
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define YAS530_DEVICE_ID		0x01 /* YAS530 (MS-3E) */
9862306a36Sopenharmony_ci#define YAS530_VERSION_A		0 /* YAS530 (MS-3E A) */
9962306a36Sopenharmony_ci#define YAS530_VERSION_B		1 /* YAS530B (MS-3E B) */
10062306a36Sopenharmony_ci#define YAS530_VERSION_A_COEF		380
10162306a36Sopenharmony_ci#define YAS530_VERSION_B_COEF		550
10262306a36Sopenharmony_ci#define YAS530_DATA_BITS		12
10362306a36Sopenharmony_ci#define YAS530_DATA_CENTER		BIT(YAS530_DATA_BITS - 1)
10462306a36Sopenharmony_ci#define YAS530_DATA_OVERFLOW		(BIT(YAS530_DATA_BITS) - 1)
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define YAS532_DEVICE_ID		0x02 /* YAS532/YAS533 (MS-3R/F) */
10762306a36Sopenharmony_ci#define YAS532_VERSION_AB		0 /* YAS532/533 AB (MS-3R/F AB) */
10862306a36Sopenharmony_ci#define YAS532_VERSION_AC		1 /* YAS532/533 AC (MS-3R/F AC) */
10962306a36Sopenharmony_ci#define YAS532_VERSION_AB_COEF		1800
11062306a36Sopenharmony_ci#define YAS532_VERSION_AC_COEF_X	850
11162306a36Sopenharmony_ci#define YAS532_VERSION_AC_COEF_Y1	750
11262306a36Sopenharmony_ci#define YAS532_VERSION_AC_COEF_Y2	750
11362306a36Sopenharmony_ci#define YAS532_DATA_BITS		13
11462306a36Sopenharmony_ci#define YAS532_DATA_CENTER		BIT(YAS532_DATA_BITS - 1)
11562306a36Sopenharmony_ci#define YAS532_DATA_OVERFLOW		(BIT(YAS532_DATA_BITS) - 1)
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define YAS537_DEVICE_ID		0x07 /* YAS537 (MS-3T) */
11862306a36Sopenharmony_ci#define YAS537_VERSION_0		0 /* Version naming unknown */
11962306a36Sopenharmony_ci#define YAS537_VERSION_1		1 /* Version naming unknown */
12062306a36Sopenharmony_ci#define YAS537_MAG_AVERAGE_32_MASK	GENMASK(6, 4)
12162306a36Sopenharmony_ci#define YAS537_MEASURE_TIME_WORST_US	1500
12262306a36Sopenharmony_ci#define YAS537_DEFAULT_SENSOR_DELAY_MS	50
12362306a36Sopenharmony_ci#define YAS537_MAG_RCOIL_TIME_US	65
12462306a36Sopenharmony_ci#define YAS537_MTC3_MASK_PREP		GENMASK(7, 0)
12562306a36Sopenharmony_ci#define YAS537_MTC3_MASK_GET		GENMASK(7, 5)
12662306a36Sopenharmony_ci#define YAS537_MTC3_ADD_BIT		BIT(4)
12762306a36Sopenharmony_ci#define YAS537_HCK_MASK_PREP		GENMASK(4, 0)
12862306a36Sopenharmony_ci#define YAS537_HCK_MASK_GET		GENMASK(7, 4)
12962306a36Sopenharmony_ci#define YAS537_LCK_MASK_PREP		GENMASK(4, 0)
13062306a36Sopenharmony_ci#define YAS537_LCK_MASK_GET		GENMASK(3, 0)
13162306a36Sopenharmony_ci#define YAS537_OC_MASK_GET		GENMASK(5, 0)
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/* Turn off device regulators etc after 5 seconds of inactivity */
13462306a36Sopenharmony_ci#define YAS5XX_AUTOSUSPEND_DELAY_MS	5000
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cienum chip_ids {
13762306a36Sopenharmony_ci	yas530,
13862306a36Sopenharmony_ci	yas532,
13962306a36Sopenharmony_ci	yas533,
14062306a36Sopenharmony_ci	yas537,
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic const int yas530_volatile_reg[] = {
14462306a36Sopenharmony_ci	YAS530_ACTUATE_INIT_COIL,
14562306a36Sopenharmony_ci	YAS530_MEASURE,
14662306a36Sopenharmony_ci};
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic const int yas537_volatile_reg[] = {
14962306a36Sopenharmony_ci	YAS537_MEASURE,
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistruct yas5xx_calibration {
15362306a36Sopenharmony_ci	/* Linearization calibration x, y1, y2 */
15462306a36Sopenharmony_ci	s32 r[3];
15562306a36Sopenharmony_ci	u32 f[3];
15662306a36Sopenharmony_ci	/* Temperature compensation calibration */
15762306a36Sopenharmony_ci	s16 Cx, Cy1, Cy2;
15862306a36Sopenharmony_ci	/* Misc calibration coefficients */
15962306a36Sopenharmony_ci	s8  a2, a3, a4, a6, a7, a8;
16062306a36Sopenharmony_ci	s16 a5, a9;
16162306a36Sopenharmony_ci	u8  k;
16262306a36Sopenharmony_ci	/* clock divider */
16362306a36Sopenharmony_ci	u8 dck;
16462306a36Sopenharmony_ci};
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistruct yas5xx;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/**
16962306a36Sopenharmony_ci * struct yas5xx_chip_info - device-specific data and function pointers
17062306a36Sopenharmony_ci * @devid: device ID number
17162306a36Sopenharmony_ci * @product_name: product name of the YAS variant
17262306a36Sopenharmony_ci * @version_names: version letters or namings
17362306a36Sopenharmony_ci * @volatile_reg: device-specific volatile registers
17462306a36Sopenharmony_ci * @volatile_reg_qty: quantity of device-specific volatile registers
17562306a36Sopenharmony_ci * @scaling_val2: scaling value for IIO_CHAN_INFO_SCALE
17662306a36Sopenharmony_ci * @t_ref: number of counts at reference temperature 20 °C
17762306a36Sopenharmony_ci * @min_temp_x10: starting point of temperature counting in 1/10:s degrees Celsius
17862306a36Sopenharmony_ci * @get_measure: function pointer to get a measurement
17962306a36Sopenharmony_ci * @get_calibration_data: function pointer to get calibration data
18062306a36Sopenharmony_ci * @dump_calibration: function pointer to dump calibration for debugging
18162306a36Sopenharmony_ci * @measure_offsets: function pointer to measure the offsets
18262306a36Sopenharmony_ci * @power_on: function pointer to power-on procedure
18362306a36Sopenharmony_ci *
18462306a36Sopenharmony_ci * The "t_ref" value for YAS532/533 is known from the Android driver.
18562306a36Sopenharmony_ci * For YAS530 and YAS537 it was approximately measured.
18662306a36Sopenharmony_ci *
18762306a36Sopenharmony_ci * The temperatures "min_temp_x10" are derived from the temperature resolutions
18862306a36Sopenharmony_ci * given in the data sheets.
18962306a36Sopenharmony_ci */
19062306a36Sopenharmony_cistruct yas5xx_chip_info {
19162306a36Sopenharmony_ci	unsigned int devid;
19262306a36Sopenharmony_ci	const char *product_name;
19362306a36Sopenharmony_ci	const char *version_names[2];
19462306a36Sopenharmony_ci	const int *volatile_reg;
19562306a36Sopenharmony_ci	int volatile_reg_qty;
19662306a36Sopenharmony_ci	u32 scaling_val2;
19762306a36Sopenharmony_ci	u16 t_ref;
19862306a36Sopenharmony_ci	s16 min_temp_x10;
19962306a36Sopenharmony_ci	int (*get_measure)(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo);
20062306a36Sopenharmony_ci	int (*get_calibration_data)(struct yas5xx *yas5xx);
20162306a36Sopenharmony_ci	void (*dump_calibration)(struct yas5xx *yas5xx);
20262306a36Sopenharmony_ci	int (*measure_offsets)(struct yas5xx *yas5xx);
20362306a36Sopenharmony_ci	int (*power_on)(struct yas5xx *yas5xx);
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/**
20762306a36Sopenharmony_ci * struct yas5xx - state container for the YAS5xx driver
20862306a36Sopenharmony_ci * @dev: parent device pointer
20962306a36Sopenharmony_ci * @chip_info: device-specific data and function pointers
21062306a36Sopenharmony_ci * @version: device version
21162306a36Sopenharmony_ci * @calibration: calibration settings from the OTP storage
21262306a36Sopenharmony_ci * @hard_offsets: offsets for each axis measured with initcoil actuated
21362306a36Sopenharmony_ci * @orientation: mounting matrix, flipped axis etc
21462306a36Sopenharmony_ci * @map: regmap to access the YAX5xx registers over I2C
21562306a36Sopenharmony_ci * @regs: the vdd and vddio power regulators
21662306a36Sopenharmony_ci * @reset: optional GPIO line used for handling RESET
21762306a36Sopenharmony_ci * @lock: locks the magnetometer for exclusive use during a measurement (which
21862306a36Sopenharmony_ci * involves several register transactions so the regmap lock is not enough)
21962306a36Sopenharmony_ci * so that measurements get serialized in a first-come-first serve manner
22062306a36Sopenharmony_ci * @scan: naturally aligned measurements
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_cistruct yas5xx {
22362306a36Sopenharmony_ci	struct device *dev;
22462306a36Sopenharmony_ci	const struct yas5xx_chip_info *chip_info;
22562306a36Sopenharmony_ci	unsigned int version;
22662306a36Sopenharmony_ci	struct yas5xx_calibration calibration;
22762306a36Sopenharmony_ci	s8 hard_offsets[3];
22862306a36Sopenharmony_ci	struct iio_mount_matrix orientation;
22962306a36Sopenharmony_ci	struct regmap *map;
23062306a36Sopenharmony_ci	struct regulator_bulk_data regs[2];
23162306a36Sopenharmony_ci	struct gpio_desc *reset;
23262306a36Sopenharmony_ci	struct mutex lock;
23362306a36Sopenharmony_ci	/*
23462306a36Sopenharmony_ci	 * The scanout is 4 x 32 bits in CPU endianness.
23562306a36Sopenharmony_ci	 * Ensure timestamp is naturally aligned
23662306a36Sopenharmony_ci	 */
23762306a36Sopenharmony_ci	struct {
23862306a36Sopenharmony_ci		s32 channels[4];
23962306a36Sopenharmony_ci		s64 ts __aligned(8);
24062306a36Sopenharmony_ci	} scan;
24162306a36Sopenharmony_ci};
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci/* On YAS530 the x, y1 and y2 values are 12 bits */
24462306a36Sopenharmony_cistatic u16 yas530_extract_axis(u8 *data)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	u16 val;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/*
24962306a36Sopenharmony_ci	 * These are the bits used in a 16bit word:
25062306a36Sopenharmony_ci	 * 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
25162306a36Sopenharmony_ci	 *    x  x  x  x  x  x  x  x  x  x  x  x
25262306a36Sopenharmony_ci	 */
25362306a36Sopenharmony_ci	val = get_unaligned_be16(&data[0]);
25462306a36Sopenharmony_ci	val = FIELD_GET(GENMASK(14, 3), val);
25562306a36Sopenharmony_ci	return val;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/* On YAS532 the x, y1 and y2 values are 13 bits */
25962306a36Sopenharmony_cistatic u16 yas532_extract_axis(u8 *data)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	u16 val;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/*
26462306a36Sopenharmony_ci	 * These are the bits used in a 16bit word:
26562306a36Sopenharmony_ci	 * 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
26662306a36Sopenharmony_ci	 *    x  x  x  x  x  x  x  x  x  x  x  x  x
26762306a36Sopenharmony_ci	 */
26862306a36Sopenharmony_ci	val = get_unaligned_be16(&data[0]);
26962306a36Sopenharmony_ci	val = FIELD_GET(GENMASK(14, 2), val);
27062306a36Sopenharmony_ci	return val;
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/**
27462306a36Sopenharmony_ci * yas530_measure() - Make a measure from the hardware
27562306a36Sopenharmony_ci * @yas5xx: The device state
27662306a36Sopenharmony_ci * @t: the raw temperature measurement
27762306a36Sopenharmony_ci * @x: the raw x axis measurement
27862306a36Sopenharmony_ci * @y1: the y1 axis measurement
27962306a36Sopenharmony_ci * @y2: the y2 axis measurement
28062306a36Sopenharmony_ci * @return: 0 on success or error code
28162306a36Sopenharmony_ci *
28262306a36Sopenharmony_ci * Used by YAS530, YAS532 and YAS533.
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_cistatic int yas530_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci = yas5xx->chip_info;
28762306a36Sopenharmony_ci	unsigned int busy;
28862306a36Sopenharmony_ci	u8 data[8];
28962306a36Sopenharmony_ci	int ret;
29062306a36Sopenharmony_ci	u16 val;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	mutex_lock(&yas5xx->lock);
29362306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS530_MEASURE, YAS5XX_MEASURE_START);
29462306a36Sopenharmony_ci	if (ret < 0)
29562306a36Sopenharmony_ci		goto out_unlock;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/*
29862306a36Sopenharmony_ci	 * Typical time to measure 1500 us, max 2000 us so wait min 500 us
29962306a36Sopenharmony_ci	 * and at most 20000 us (one magnitude more than the datsheet max)
30062306a36Sopenharmony_ci	 * before timeout.
30162306a36Sopenharmony_ci	 */
30262306a36Sopenharmony_ci	ret = regmap_read_poll_timeout(yas5xx->map, YAS5XX_MEASURE_DATA, busy,
30362306a36Sopenharmony_ci				       !(busy & YAS5XX_MEASURE_DATA_BUSY),
30462306a36Sopenharmony_ci				       500, 20000);
30562306a36Sopenharmony_ci	if (ret) {
30662306a36Sopenharmony_ci		dev_err(yas5xx->dev, "timeout waiting for measurement\n");
30762306a36Sopenharmony_ci		goto out_unlock;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ret = regmap_bulk_read(yas5xx->map, YAS5XX_MEASURE_DATA,
31162306a36Sopenharmony_ci			       data, sizeof(data));
31262306a36Sopenharmony_ci	if (ret)
31362306a36Sopenharmony_ci		goto out_unlock;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	mutex_unlock(&yas5xx->lock);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	switch (ci->devid) {
31862306a36Sopenharmony_ci	case YAS530_DEVICE_ID:
31962306a36Sopenharmony_ci		/*
32062306a36Sopenharmony_ci		 * The t value is 9 bits in big endian format
32162306a36Sopenharmony_ci		 * These are the bits used in a 16bit word:
32262306a36Sopenharmony_ci		 * 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
32362306a36Sopenharmony_ci		 *    x  x  x  x  x  x  x  x  x
32462306a36Sopenharmony_ci		 */
32562306a36Sopenharmony_ci		val = get_unaligned_be16(&data[0]);
32662306a36Sopenharmony_ci		val = FIELD_GET(GENMASK(14, 6), val);
32762306a36Sopenharmony_ci		*t = val;
32862306a36Sopenharmony_ci		*x = yas530_extract_axis(&data[2]);
32962306a36Sopenharmony_ci		*y1 = yas530_extract_axis(&data[4]);
33062306a36Sopenharmony_ci		*y2 = yas530_extract_axis(&data[6]);
33162306a36Sopenharmony_ci		break;
33262306a36Sopenharmony_ci	case YAS532_DEVICE_ID:
33362306a36Sopenharmony_ci		/*
33462306a36Sopenharmony_ci		 * The t value is 10 bits in big endian format
33562306a36Sopenharmony_ci		 * These are the bits used in a 16bit word:
33662306a36Sopenharmony_ci		 * 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
33762306a36Sopenharmony_ci		 *    x  x  x  x  x  x  x  x  x  x
33862306a36Sopenharmony_ci		 */
33962306a36Sopenharmony_ci		val = get_unaligned_be16(&data[0]);
34062306a36Sopenharmony_ci		val = FIELD_GET(GENMASK(14, 5), val);
34162306a36Sopenharmony_ci		*t = val;
34262306a36Sopenharmony_ci		*x = yas532_extract_axis(&data[2]);
34362306a36Sopenharmony_ci		*y1 = yas532_extract_axis(&data[4]);
34462306a36Sopenharmony_ci		*y2 = yas532_extract_axis(&data[6]);
34562306a36Sopenharmony_ci		break;
34662306a36Sopenharmony_ci	default:
34762306a36Sopenharmony_ci		dev_err(yas5xx->dev, "unknown data format\n");
34862306a36Sopenharmony_ci		ret = -EINVAL;
34962306a36Sopenharmony_ci		break;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	return ret;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ciout_unlock:
35562306a36Sopenharmony_ci	mutex_unlock(&yas5xx->lock);
35662306a36Sopenharmony_ci	return ret;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/**
36062306a36Sopenharmony_ci * yas537_measure() - Make a measure from the hardware
36162306a36Sopenharmony_ci * @yas5xx: The device state
36262306a36Sopenharmony_ci * @t: the raw temperature measurement
36362306a36Sopenharmony_ci * @x: the raw x axis measurement
36462306a36Sopenharmony_ci * @y1: the y1 axis measurement
36562306a36Sopenharmony_ci * @y2: the y2 axis measurement
36662306a36Sopenharmony_ci * @return: 0 on success or error code
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_cistatic int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct yas5xx_calibration *c = &yas5xx->calibration;
37162306a36Sopenharmony_ci	unsigned int busy;
37262306a36Sopenharmony_ci	u8 data[8];
37362306a36Sopenharmony_ci	u16 xy1y2[3];
37462306a36Sopenharmony_ci	s32 h[3], s[3];
37562306a36Sopenharmony_ci	int i, ret;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	mutex_lock(&yas5xx->lock);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* Contrary to YAS530/532, also a "cont" bit is set, meaning unknown */
38062306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS537_MEASURE, YAS5XX_MEASURE_START |
38162306a36Sopenharmony_ci			   YAS5XX_MEASURE_CONT);
38262306a36Sopenharmony_ci	if (ret < 0)
38362306a36Sopenharmony_ci		goto out_unlock;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* Use same timeout like YAS530/532 but the bit is in data row 2 */
38662306a36Sopenharmony_ci	ret = regmap_read_poll_timeout(yas5xx->map, YAS5XX_MEASURE_DATA + 2, busy,
38762306a36Sopenharmony_ci				       !(busy & YAS5XX_MEASURE_DATA_BUSY),
38862306a36Sopenharmony_ci				       500, 20000);
38962306a36Sopenharmony_ci	if (ret) {
39062306a36Sopenharmony_ci		dev_err(yas5xx->dev, "timeout waiting for measurement\n");
39162306a36Sopenharmony_ci		goto out_unlock;
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	ret = regmap_bulk_read(yas5xx->map, YAS5XX_MEASURE_DATA,
39562306a36Sopenharmony_ci			       data, sizeof(data));
39662306a36Sopenharmony_ci	if (ret)
39762306a36Sopenharmony_ci		goto out_unlock;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	mutex_unlock(&yas5xx->lock);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	*t = get_unaligned_be16(&data[0]);
40262306a36Sopenharmony_ci	xy1y2[0] = FIELD_GET(GENMASK(13, 0), get_unaligned_be16(&data[2]));
40362306a36Sopenharmony_ci	xy1y2[1] = get_unaligned_be16(&data[4]);
40462306a36Sopenharmony_ci	xy1y2[2] = get_unaligned_be16(&data[6]);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* The second version of YAS537 needs to include calibration coefficients */
40762306a36Sopenharmony_ci	if (yas5xx->version == YAS537_VERSION_1) {
40862306a36Sopenharmony_ci		for (i = 0; i < 3; i++)
40962306a36Sopenharmony_ci			s[i] = xy1y2[i] - BIT(13);
41062306a36Sopenharmony_ci		h[0] = (c->k *   (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / BIT(13);
41162306a36Sopenharmony_ci		h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / BIT(13);
41262306a36Sopenharmony_ci		h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / BIT(13);
41362306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
41462306a36Sopenharmony_ci			clamp_val(h[i], -BIT(13), BIT(13) - 1);
41562306a36Sopenharmony_ci			xy1y2[i] = h[i] + BIT(13);
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	*x = xy1y2[0];
42062306a36Sopenharmony_ci	*y1 = xy1y2[1];
42162306a36Sopenharmony_ci	*y2 = xy1y2[2];
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	return 0;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ciout_unlock:
42662306a36Sopenharmony_ci	mutex_unlock(&yas5xx->lock);
42762306a36Sopenharmony_ci	return ret;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci/* Used by YAS530, YAS532 and YAS533 */
43162306a36Sopenharmony_cistatic s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci = yas5xx->chip_info;
43462306a36Sopenharmony_ci	struct yas5xx_calibration *c = &yas5xx->calibration;
43562306a36Sopenharmony_ci	static const s32 yas532ac_coef[] = {
43662306a36Sopenharmony_ci		YAS532_VERSION_AC_COEF_X,
43762306a36Sopenharmony_ci		YAS532_VERSION_AC_COEF_Y1,
43862306a36Sopenharmony_ci		YAS532_VERSION_AC_COEF_Y2,
43962306a36Sopenharmony_ci	};
44062306a36Sopenharmony_ci	s32 coef;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	/* Select coefficients */
44362306a36Sopenharmony_ci	switch (ci->devid) {
44462306a36Sopenharmony_ci	case YAS530_DEVICE_ID:
44562306a36Sopenharmony_ci		if (yas5xx->version == YAS530_VERSION_A)
44662306a36Sopenharmony_ci			coef = YAS530_VERSION_A_COEF;
44762306a36Sopenharmony_ci		else
44862306a36Sopenharmony_ci			coef = YAS530_VERSION_B_COEF;
44962306a36Sopenharmony_ci		break;
45062306a36Sopenharmony_ci	case YAS532_DEVICE_ID:
45162306a36Sopenharmony_ci		if (yas5xx->version == YAS532_VERSION_AB)
45262306a36Sopenharmony_ci			coef = YAS532_VERSION_AB_COEF;
45362306a36Sopenharmony_ci		else
45462306a36Sopenharmony_ci			/* Elaborate coefficients */
45562306a36Sopenharmony_ci			coef = yas532ac_coef[axis];
45662306a36Sopenharmony_ci		break;
45762306a36Sopenharmony_ci	default:
45862306a36Sopenharmony_ci		dev_err(yas5xx->dev, "unknown device type\n");
45962306a36Sopenharmony_ci		return val;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci	/*
46262306a36Sopenharmony_ci	 * Linearization formula:
46362306a36Sopenharmony_ci	 *
46462306a36Sopenharmony_ci	 * x' = x - (3721 + 50 * f) + (xoffset - r) * c
46562306a36Sopenharmony_ci	 *
46662306a36Sopenharmony_ci	 * Where f and r are calibration values, c is a per-device
46762306a36Sopenharmony_ci	 * and sometimes per-axis coefficient.
46862306a36Sopenharmony_ci	 */
46962306a36Sopenharmony_ci	return val - (3721 + 50 * c->f[axis]) +
47062306a36Sopenharmony_ci		(yas5xx->hard_offsets[axis] - c->r[axis]) * coef;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic s32 yas5xx_calc_temperature(struct yas5xx *yas5xx, u16 t)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci = yas5xx->chip_info;
47662306a36Sopenharmony_ci	s32 to;
47762306a36Sopenharmony_ci	u16 t_ref;
47862306a36Sopenharmony_ci	s16 min_temp_x10;
47962306a36Sopenharmony_ci	int ref_temp_x10;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	t_ref = ci->t_ref;
48262306a36Sopenharmony_ci	min_temp_x10 = ci->min_temp_x10;
48362306a36Sopenharmony_ci	ref_temp_x10 = 200;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	to = (min_temp_x10 + ((ref_temp_x10 - min_temp_x10) * t / t_ref)) * 100;
48662306a36Sopenharmony_ci	return to;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/**
49062306a36Sopenharmony_ci * yas530_get_measure() - Measure a sample of all axis and process
49162306a36Sopenharmony_ci * @yas5xx: The device state
49262306a36Sopenharmony_ci * @to: Temperature out
49362306a36Sopenharmony_ci * @xo: X axis out
49462306a36Sopenharmony_ci * @yo: Y axis out
49562306a36Sopenharmony_ci * @zo: Z axis out
49662306a36Sopenharmony_ci * @return: 0 on success or error code
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * Used by YAS530, YAS532 and YAS533.
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_cistatic int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci = yas5xx->chip_info;
50362306a36Sopenharmony_ci	struct yas5xx_calibration *c = &yas5xx->calibration;
50462306a36Sopenharmony_ci	u16 t_ref, t_comp, t, x, y1, y2;
50562306a36Sopenharmony_ci	/* These are signed x, signed y1 etc */
50662306a36Sopenharmony_ci	s32 sx, sy1, sy2, sy, sz;
50762306a36Sopenharmony_ci	int ret;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/* We first get raw data that needs to be translated to [x,y,z] */
51062306a36Sopenharmony_ci	ret = yas530_measure(yas5xx, &t, &x, &y1, &y2);
51162306a36Sopenharmony_ci	if (ret)
51262306a36Sopenharmony_ci		return ret;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/* Do some linearization if available */
51562306a36Sopenharmony_ci	sx = yas530_linearize(yas5xx, x, 0);
51662306a36Sopenharmony_ci	sy1 = yas530_linearize(yas5xx, y1, 1);
51762306a36Sopenharmony_ci	sy2 = yas530_linearize(yas5xx, y2, 2);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/*
52062306a36Sopenharmony_ci	 * Set the temperature for compensation (unit: counts):
52162306a36Sopenharmony_ci	 * YAS532/YAS533 version AC uses the temperature deviation as a
52262306a36Sopenharmony_ci	 * multiplier. YAS530 and YAS532 version AB use solely the t value.
52362306a36Sopenharmony_ci	 */
52462306a36Sopenharmony_ci	t_ref = ci->t_ref;
52562306a36Sopenharmony_ci	if (ci->devid == YAS532_DEVICE_ID &&
52662306a36Sopenharmony_ci	    yas5xx->version == YAS532_VERSION_AC) {
52762306a36Sopenharmony_ci		t_comp = t - t_ref;
52862306a36Sopenharmony_ci	} else {
52962306a36Sopenharmony_ci		t_comp = t;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/*
53362306a36Sopenharmony_ci	 * Temperature compensation for x, y1, y2 respectively:
53462306a36Sopenharmony_ci	 *
53562306a36Sopenharmony_ci	 *          Cx * t_comp
53662306a36Sopenharmony_ci	 * x' = x - -----------
53762306a36Sopenharmony_ci	 *              100
53862306a36Sopenharmony_ci	 */
53962306a36Sopenharmony_ci	sx = sx - (c->Cx * t_comp) / 100;
54062306a36Sopenharmony_ci	sy1 = sy1 - (c->Cy1 * t_comp) / 100;
54162306a36Sopenharmony_ci	sy2 = sy2 - (c->Cy2 * t_comp) / 100;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/*
54462306a36Sopenharmony_ci	 * Break y1 and y2 into y and z, y1 and y2 are apparently encoding
54562306a36Sopenharmony_ci	 * y and z.
54662306a36Sopenharmony_ci	 */
54762306a36Sopenharmony_ci	sy = sy1 - sy2;
54862306a36Sopenharmony_ci	sz = -sy1 - sy2;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	/* Calculate temperature readout */
55162306a36Sopenharmony_ci	*to = yas5xx_calc_temperature(yas5xx, t);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/*
55462306a36Sopenharmony_ci	 * Calibrate [x,y,z] with some formulas like this:
55562306a36Sopenharmony_ci	 *
55662306a36Sopenharmony_ci	 *            100 * x + a_2 * y + a_3 * z
55762306a36Sopenharmony_ci	 *  x' = k *  ---------------------------
55862306a36Sopenharmony_ci	 *                        10
55962306a36Sopenharmony_ci	 *
56062306a36Sopenharmony_ci	 *           a_4 * x + a_5 * y + a_6 * z
56162306a36Sopenharmony_ci	 *  y' = k * ---------------------------
56262306a36Sopenharmony_ci	 *                        10
56362306a36Sopenharmony_ci	 *
56462306a36Sopenharmony_ci	 *           a_7 * x + a_8 * y + a_9 * z
56562306a36Sopenharmony_ci	 *  z' = k * ---------------------------
56662306a36Sopenharmony_ci	 *                        10
56762306a36Sopenharmony_ci	 */
56862306a36Sopenharmony_ci	*xo = c->k * ((100 * sx + c->a2 * sy + c->a3 * sz) / 10);
56962306a36Sopenharmony_ci	*yo = c->k * ((c->a4 * sx + c->a5 * sy + c->a6 * sz) / 10);
57062306a36Sopenharmony_ci	*zo = c->k * ((c->a7 * sx + c->a8 * sy + c->a9 * sz) / 10);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	return 0;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/**
57662306a36Sopenharmony_ci * yas537_get_measure() - Measure a sample of all axis and process
57762306a36Sopenharmony_ci * @yas5xx: The device state
57862306a36Sopenharmony_ci * @to: Temperature out
57962306a36Sopenharmony_ci * @xo: X axis out
58062306a36Sopenharmony_ci * @yo: Y axis out
58162306a36Sopenharmony_ci * @zo: Z axis out
58262306a36Sopenharmony_ci * @return: 0 on success or error code
58362306a36Sopenharmony_ci */
58462306a36Sopenharmony_cistatic int yas537_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	u16 t, x, y1, y2;
58762306a36Sopenharmony_ci	int ret;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	/* We first get raw data that needs to be translated to [x,y,z] */
59062306a36Sopenharmony_ci	ret = yas537_measure(yas5xx, &t, &x, &y1, &y2);
59162306a36Sopenharmony_ci	if (ret)
59262306a36Sopenharmony_ci		return ret;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/* Calculate temperature readout */
59562306a36Sopenharmony_ci	*to = yas5xx_calc_temperature(yas5xx, t);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/*
59862306a36Sopenharmony_ci	 * Unfortunately, no linearization or temperature compensation formulas
59962306a36Sopenharmony_ci	 * are known for YAS537.
60062306a36Sopenharmony_ci	 */
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* Calculate x, y, z from x, y1, y2 */
60362306a36Sopenharmony_ci	*xo = (x - BIT(13)) * 300;
60462306a36Sopenharmony_ci	*yo = (y1 - y2) * 1732 / 10;
60562306a36Sopenharmony_ci	*zo = (-y1 - y2 + BIT(14)) * 300;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	return 0;
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic int yas5xx_read_raw(struct iio_dev *indio_dev,
61162306a36Sopenharmony_ci			   struct iio_chan_spec const *chan,
61262306a36Sopenharmony_ci			   int *val, int *val2,
61362306a36Sopenharmony_ci			   long mask)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	struct yas5xx *yas5xx = iio_priv(indio_dev);
61662306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci = yas5xx->chip_info;
61762306a36Sopenharmony_ci	s32 t, x, y, z;
61862306a36Sopenharmony_ci	int ret;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	switch (mask) {
62162306a36Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
62262306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
62362306a36Sopenharmony_ci		pm_runtime_get_sync(yas5xx->dev);
62462306a36Sopenharmony_ci		ret = ci->get_measure(yas5xx, &t, &x, &y, &z);
62562306a36Sopenharmony_ci		pm_runtime_mark_last_busy(yas5xx->dev);
62662306a36Sopenharmony_ci		pm_runtime_put_autosuspend(yas5xx->dev);
62762306a36Sopenharmony_ci		if (ret)
62862306a36Sopenharmony_ci			return ret;
62962306a36Sopenharmony_ci		switch (chan->address) {
63062306a36Sopenharmony_ci		case 0:
63162306a36Sopenharmony_ci			*val = t;
63262306a36Sopenharmony_ci			break;
63362306a36Sopenharmony_ci		case 1:
63462306a36Sopenharmony_ci			*val = x;
63562306a36Sopenharmony_ci			break;
63662306a36Sopenharmony_ci		case 2:
63762306a36Sopenharmony_ci			*val = y;
63862306a36Sopenharmony_ci			break;
63962306a36Sopenharmony_ci		case 3:
64062306a36Sopenharmony_ci			*val = z;
64162306a36Sopenharmony_ci			break;
64262306a36Sopenharmony_ci		default:
64362306a36Sopenharmony_ci			dev_err(yas5xx->dev, "unknown channel\n");
64462306a36Sopenharmony_ci			return -EINVAL;
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci		return IIO_VAL_INT;
64762306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
64862306a36Sopenharmony_ci		*val = 1;
64962306a36Sopenharmony_ci		*val2 = ci->scaling_val2;
65062306a36Sopenharmony_ci		return IIO_VAL_FRACTIONAL;
65162306a36Sopenharmony_ci	default:
65262306a36Sopenharmony_ci		/* Unknown request */
65362306a36Sopenharmony_ci		return -EINVAL;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic void yas5xx_fill_buffer(struct iio_dev *indio_dev)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct yas5xx *yas5xx = iio_priv(indio_dev);
66062306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci = yas5xx->chip_info;
66162306a36Sopenharmony_ci	s32 t, x, y, z;
66262306a36Sopenharmony_ci	int ret;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	pm_runtime_get_sync(yas5xx->dev);
66562306a36Sopenharmony_ci	ret = ci->get_measure(yas5xx, &t, &x, &y, &z);
66662306a36Sopenharmony_ci	pm_runtime_mark_last_busy(yas5xx->dev);
66762306a36Sopenharmony_ci	pm_runtime_put_autosuspend(yas5xx->dev);
66862306a36Sopenharmony_ci	if (ret) {
66962306a36Sopenharmony_ci		dev_err(yas5xx->dev, "error refilling buffer\n");
67062306a36Sopenharmony_ci		return;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci	yas5xx->scan.channels[0] = t;
67362306a36Sopenharmony_ci	yas5xx->scan.channels[1] = x;
67462306a36Sopenharmony_ci	yas5xx->scan.channels[2] = y;
67562306a36Sopenharmony_ci	yas5xx->scan.channels[3] = z;
67662306a36Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev, &yas5xx->scan,
67762306a36Sopenharmony_ci					   iio_get_time_ns(indio_dev));
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic irqreturn_t yas5xx_handle_trigger(int irq, void *p)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	const struct iio_poll_func *pf = p;
68362306a36Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	yas5xx_fill_buffer(indio_dev);
68662306a36Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	return IRQ_HANDLED;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic const struct iio_mount_matrix *
69362306a36Sopenharmony_ciyas5xx_get_mount_matrix(const struct iio_dev *indio_dev,
69462306a36Sopenharmony_ci			const struct iio_chan_spec *chan)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	struct yas5xx *yas5xx = iio_priv(indio_dev);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	return &yas5xx->orientation;
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic const struct iio_chan_spec_ext_info yas5xx_ext_info[] = {
70262306a36Sopenharmony_ci	IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, yas5xx_get_mount_matrix),
70362306a36Sopenharmony_ci	{ }
70462306a36Sopenharmony_ci};
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci#define YAS5XX_AXIS_CHANNEL(axis, index)				\
70762306a36Sopenharmony_ci	{								\
70862306a36Sopenharmony_ci		.type = IIO_MAGN,					\
70962306a36Sopenharmony_ci		.modified = 1,						\
71062306a36Sopenharmony_ci		.channel2 = IIO_MOD_##axis,				\
71162306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
71262306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE),			\
71362306a36Sopenharmony_ci		.ext_info = yas5xx_ext_info,				\
71462306a36Sopenharmony_ci		.address = index,					\
71562306a36Sopenharmony_ci		.scan_index = index,					\
71662306a36Sopenharmony_ci		.scan_type = {						\
71762306a36Sopenharmony_ci			.sign = 's',					\
71862306a36Sopenharmony_ci			.realbits = 32,					\
71962306a36Sopenharmony_ci			.storagebits = 32,				\
72062306a36Sopenharmony_ci			.endianness = IIO_CPU,				\
72162306a36Sopenharmony_ci		},							\
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic const struct iio_chan_spec yas5xx_channels[] = {
72562306a36Sopenharmony_ci	{
72662306a36Sopenharmony_ci		.type = IIO_TEMP,
72762306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
72862306a36Sopenharmony_ci		.address = 0,
72962306a36Sopenharmony_ci		.scan_index = 0,
73062306a36Sopenharmony_ci		.scan_type = {
73162306a36Sopenharmony_ci			.sign = 's',
73262306a36Sopenharmony_ci			.realbits = 32,
73362306a36Sopenharmony_ci			.storagebits = 32,
73462306a36Sopenharmony_ci			.endianness = IIO_CPU,
73562306a36Sopenharmony_ci		},
73662306a36Sopenharmony_ci	},
73762306a36Sopenharmony_ci	YAS5XX_AXIS_CHANNEL(X, 1),
73862306a36Sopenharmony_ci	YAS5XX_AXIS_CHANNEL(Y, 2),
73962306a36Sopenharmony_ci	YAS5XX_AXIS_CHANNEL(Z, 3),
74062306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(4),
74162306a36Sopenharmony_ci};
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic const unsigned long yas5xx_scan_masks[] = { GENMASK(3, 0), 0 };
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic const struct iio_info yas5xx_info = {
74662306a36Sopenharmony_ci	.read_raw = &yas5xx_read_raw,
74762306a36Sopenharmony_ci};
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_cistatic bool yas5xx_volatile_reg(struct device *dev, unsigned int reg)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
75262306a36Sopenharmony_ci	struct yas5xx *yas5xx = iio_priv(indio_dev);
75362306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci = yas5xx->chip_info;
75462306a36Sopenharmony_ci	int reg_qty;
75562306a36Sopenharmony_ci	int i;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (reg >= YAS5XX_MEASURE_DATA && reg < YAS5XX_MEASURE_DATA + 8)
75862306a36Sopenharmony_ci		return true;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	/*
76162306a36Sopenharmony_ci	 * YAS versions share different registers on the same address,
76262306a36Sopenharmony_ci	 * need to differentiate.
76362306a36Sopenharmony_ci	 */
76462306a36Sopenharmony_ci	reg_qty = ci->volatile_reg_qty;
76562306a36Sopenharmony_ci	for (i = 0; i < reg_qty; i++) {
76662306a36Sopenharmony_ci		if (reg == ci->volatile_reg[i])
76762306a36Sopenharmony_ci			return true;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	return false;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci/* TODO: enable regmap cache, using mark dirty and sync at runtime resume */
77462306a36Sopenharmony_cistatic const struct regmap_config yas5xx_regmap_config = {
77562306a36Sopenharmony_ci	.reg_bits = 8,
77662306a36Sopenharmony_ci	.val_bits = 8,
77762306a36Sopenharmony_ci	.max_register = 0xff,
77862306a36Sopenharmony_ci	.volatile_reg = yas5xx_volatile_reg,
77962306a36Sopenharmony_ci};
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci/**
78262306a36Sopenharmony_ci * yas530_extract_calibration() - extracts the a2-a9 and k calibration
78362306a36Sopenharmony_ci * @data: the bitfield to use
78462306a36Sopenharmony_ci * @c: the calibration to populate
78562306a36Sopenharmony_ci *
78662306a36Sopenharmony_ci * Used by YAS530, YAS532 and YAS533.
78762306a36Sopenharmony_ci */
78862306a36Sopenharmony_cistatic void yas530_extract_calibration(u8 *data, struct yas5xx_calibration *c)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	u64 val = get_unaligned_be64(data);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	/*
79362306a36Sopenharmony_ci	 * Bitfield layout for the axis calibration data, for factor
79462306a36Sopenharmony_ci	 * a2 = 2 etc, k = k, c = clock divider
79562306a36Sopenharmony_ci	 *
79662306a36Sopenharmony_ci	 * n   7 6 5 4 3 2 1 0
79762306a36Sopenharmony_ci	 * 0 [ 2 2 2 2 2 2 3 3 ] bits 63 .. 56
79862306a36Sopenharmony_ci	 * 1 [ 3 3 4 4 4 4 4 4 ] bits 55 .. 48
79962306a36Sopenharmony_ci	 * 2 [ 5 5 5 5 5 5 6 6 ] bits 47 .. 40
80062306a36Sopenharmony_ci	 * 3 [ 6 6 6 6 7 7 7 7 ] bits 39 .. 32
80162306a36Sopenharmony_ci	 * 4 [ 7 7 7 8 8 8 8 8 ] bits 31 .. 24
80262306a36Sopenharmony_ci	 * 5 [ 8 9 9 9 9 9 9 9 ] bits 23 .. 16
80362306a36Sopenharmony_ci	 * 6 [ 9 k k k k k c c ] bits 15 .. 8
80462306a36Sopenharmony_ci	 * 7 [ c x x x x x x x ] bits  7 .. 0
80562306a36Sopenharmony_ci	 */
80662306a36Sopenharmony_ci	c->a2 = FIELD_GET(GENMASK_ULL(63, 58), val) - 32;
80762306a36Sopenharmony_ci	c->a3 = FIELD_GET(GENMASK_ULL(57, 54), val) - 8;
80862306a36Sopenharmony_ci	c->a4 = FIELD_GET(GENMASK_ULL(53, 48), val) - 32;
80962306a36Sopenharmony_ci	c->a5 = FIELD_GET(GENMASK_ULL(47, 42), val) + 38;
81062306a36Sopenharmony_ci	c->a6 = FIELD_GET(GENMASK_ULL(41, 36), val) - 32;
81162306a36Sopenharmony_ci	c->a7 = FIELD_GET(GENMASK_ULL(35, 29), val) - 64;
81262306a36Sopenharmony_ci	c->a8 = FIELD_GET(GENMASK_ULL(28, 23), val) - 32;
81362306a36Sopenharmony_ci	c->a9 = FIELD_GET(GENMASK_ULL(22, 15), val);
81462306a36Sopenharmony_ci	c->k = FIELD_GET(GENMASK_ULL(14, 10), val) + 10;
81562306a36Sopenharmony_ci	c->dck = FIELD_GET(GENMASK_ULL(9, 7), val);
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic int yas530_get_calibration_data(struct yas5xx *yas5xx)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	struct yas5xx_calibration *c = &yas5xx->calibration;
82162306a36Sopenharmony_ci	u8 data[16];
82262306a36Sopenharmony_ci	u32 val;
82362306a36Sopenharmony_ci	int ret;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	/* Dummy read, first read is ALWAYS wrong */
82662306a36Sopenharmony_ci	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
82762306a36Sopenharmony_ci	if (ret)
82862306a36Sopenharmony_ci		return ret;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	/* Actual calibration readout */
83162306a36Sopenharmony_ci	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
83262306a36Sopenharmony_ci	if (ret)
83362306a36Sopenharmony_ci		return ret;
83462306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "calibration data: %16ph\n", data);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* Contribute calibration data to the input pool for kernel entropy */
83762306a36Sopenharmony_ci	add_device_randomness(data, sizeof(data));
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	/* Extract version */
84062306a36Sopenharmony_ci	yas5xx->version = data[15] & GENMASK(1, 0);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	/* Extract the calibration from the bitfield */
84362306a36Sopenharmony_ci	c->Cx = data[0] * 6 - 768;
84462306a36Sopenharmony_ci	c->Cy1 = data[1] * 6 - 768;
84562306a36Sopenharmony_ci	c->Cy2 = data[2] * 6 - 768;
84662306a36Sopenharmony_ci	yas530_extract_calibration(&data[3], c);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/*
84962306a36Sopenharmony_ci	 * Extract linearization:
85062306a36Sopenharmony_ci	 * Linearization layout in the 32 bits at byte 11:
85162306a36Sopenharmony_ci	 * The r factors are 6 bit values where bit 5 is the sign
85262306a36Sopenharmony_ci	 *
85362306a36Sopenharmony_ci	 * n    7  6  5  4  3  2  1  0
85462306a36Sopenharmony_ci	 * 0 [ xx xx xx r0 r0 r0 r0 r0 ] bits 31 .. 24
85562306a36Sopenharmony_ci	 * 1 [ r0 f0 f0 r1 r1 r1 r1 r1 ] bits 23 .. 16
85662306a36Sopenharmony_ci	 * 2 [ r1 f1 f1 r2 r2 r2 r2 r2 ] bits 15 .. 8
85762306a36Sopenharmony_ci	 * 3 [ r2 f2 f2 xx xx xx xx xx ] bits  7 .. 0
85862306a36Sopenharmony_ci	 */
85962306a36Sopenharmony_ci	val = get_unaligned_be32(&data[11]);
86062306a36Sopenharmony_ci	c->f[0] = FIELD_GET(GENMASK(22, 21), val);
86162306a36Sopenharmony_ci	c->f[1] = FIELD_GET(GENMASK(14, 13), val);
86262306a36Sopenharmony_ci	c->f[2] = FIELD_GET(GENMASK(6, 5), val);
86362306a36Sopenharmony_ci	c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5);
86462306a36Sopenharmony_ci	c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5);
86562306a36Sopenharmony_ci	c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	return 0;
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic int yas532_get_calibration_data(struct yas5xx *yas5xx)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	struct yas5xx_calibration *c = &yas5xx->calibration;
87362306a36Sopenharmony_ci	u8 data[14];
87462306a36Sopenharmony_ci	u32 val;
87562306a36Sopenharmony_ci	int ret;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* Dummy read, first read is ALWAYS wrong */
87862306a36Sopenharmony_ci	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
87962306a36Sopenharmony_ci	if (ret)
88062306a36Sopenharmony_ci		return ret;
88162306a36Sopenharmony_ci	/* Actual calibration readout */
88262306a36Sopenharmony_ci	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
88362306a36Sopenharmony_ci	if (ret)
88462306a36Sopenharmony_ci		return ret;
88562306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "calibration data: %14ph\n", data);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* Sanity check, is this all zeroes? */
88862306a36Sopenharmony_ci	if (!memchr_inv(data, 0x00, 13) && !(data[13] & BIT(7)))
88962306a36Sopenharmony_ci		dev_warn(yas5xx->dev, "calibration is blank!\n");
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	/* Contribute calibration data to the input pool for kernel entropy */
89262306a36Sopenharmony_ci	add_device_randomness(data, sizeof(data));
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	/* Only one bit of version info reserved here as far as we know */
89562306a36Sopenharmony_ci	yas5xx->version = data[13] & BIT(0);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	/* Extract calibration from the bitfield */
89862306a36Sopenharmony_ci	c->Cx = data[0] * 10 - 1280;
89962306a36Sopenharmony_ci	c->Cy1 = data[1] * 10 - 1280;
90062306a36Sopenharmony_ci	c->Cy2 = data[2] * 10 - 1280;
90162306a36Sopenharmony_ci	yas530_extract_calibration(&data[3], c);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	/*
90462306a36Sopenharmony_ci	 * Extract linearization:
90562306a36Sopenharmony_ci	 * Linearization layout in the 32 bits at byte 10:
90662306a36Sopenharmony_ci	 * The r factors are 6 bit values where bit 5 is the sign
90762306a36Sopenharmony_ci	 *
90862306a36Sopenharmony_ci	 * n    7  6  5  4  3  2  1  0
90962306a36Sopenharmony_ci	 * 0 [ xx r0 r0 r0 r0 r0 r0 f0 ] bits 31 .. 24
91062306a36Sopenharmony_ci	 * 1 [ f0 r1 r1 r1 r1 r1 r1 f1 ] bits 23 .. 16
91162306a36Sopenharmony_ci	 * 2 [ f1 r2 r2 r2 r2 r2 r2 f2 ] bits 15 .. 8
91262306a36Sopenharmony_ci	 * 3 [ f2 xx xx xx xx xx xx xx ] bits  7 .. 0
91362306a36Sopenharmony_ci	 */
91462306a36Sopenharmony_ci	val = get_unaligned_be32(&data[10]);
91562306a36Sopenharmony_ci	c->f[0] = FIELD_GET(GENMASK(24, 23), val);
91662306a36Sopenharmony_ci	c->f[1] = FIELD_GET(GENMASK(16, 15), val);
91762306a36Sopenharmony_ci	c->f[2] = FIELD_GET(GENMASK(8, 7), val);
91862306a36Sopenharmony_ci	c->r[0] = sign_extend32(FIELD_GET(GENMASK(30, 25), val), 5);
91962306a36Sopenharmony_ci	c->r[1] = sign_extend32(FIELD_GET(GENMASK(22, 17), val), 5);
92062306a36Sopenharmony_ci	c->r[2] = sign_extend32(FIELD_GET(GENMASK(14, 7), val), 5);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	return 0;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic int yas537_get_calibration_data(struct yas5xx *yas5xx)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	struct yas5xx_calibration *c = &yas5xx->calibration;
92862306a36Sopenharmony_ci	u8 data[17];
92962306a36Sopenharmony_ci	u32 val1, val2, val3, val4;
93062306a36Sopenharmony_ci	int i, ret;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	/* Writing SRST register */
93362306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS537_SRST, BIT(1));
93462306a36Sopenharmony_ci	if (ret)
93562306a36Sopenharmony_ci		return ret;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	/* Calibration readout, YAS537 needs one readout only */
93862306a36Sopenharmony_ci	ret = regmap_bulk_read(yas5xx->map, YAS537_CAL, data, sizeof(data));
93962306a36Sopenharmony_ci	if (ret)
94062306a36Sopenharmony_ci		return ret;
94162306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "calibration data: %17ph\n", data);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	/* Sanity check, is this all zeroes? */
94462306a36Sopenharmony_ci	if (!memchr_inv(data, 0x00, 16) && !FIELD_GET(GENMASK(5, 0), data[16]))
94562306a36Sopenharmony_ci		dev_warn(yas5xx->dev, "calibration is blank!\n");
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	/* Contribute calibration data to the input pool for kernel entropy */
94862306a36Sopenharmony_ci	add_device_randomness(data, sizeof(data));
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	/* Extract version information */
95162306a36Sopenharmony_ci	yas5xx->version = FIELD_GET(GENMASK(7, 6), data[16]);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	/* There are two versions of YAS537 behaving differently */
95462306a36Sopenharmony_ci	switch (yas5xx->version) {
95562306a36Sopenharmony_ci	case YAS537_VERSION_0:
95662306a36Sopenharmony_ci		/*
95762306a36Sopenharmony_ci		 * The first version simply writes data back into registers:
95862306a36Sopenharmony_ci		 *
95962306a36Sopenharmony_ci		 * data[0]  YAS537_MTC		0x93
96062306a36Sopenharmony_ci		 * data[1]			0x94
96162306a36Sopenharmony_ci		 * data[2]			0x95
96262306a36Sopenharmony_ci		 * data[3]			0x96
96362306a36Sopenharmony_ci		 * data[4]			0x97
96462306a36Sopenharmony_ci		 * data[5]			0x98
96562306a36Sopenharmony_ci		 * data[6]			0x99
96662306a36Sopenharmony_ci		 * data[7]			0x9a
96762306a36Sopenharmony_ci		 * data[8]			0x9b
96862306a36Sopenharmony_ci		 * data[9]			0x9c
96962306a36Sopenharmony_ci		 * data[10]			0x9d
97062306a36Sopenharmony_ci		 * data[11] YAS537_OC		0x9e
97162306a36Sopenharmony_ci		 *
97262306a36Sopenharmony_ci		 * data[12] YAS537_OFFSET_X	0x84
97362306a36Sopenharmony_ci		 * data[13] YAS537_OFFSET_Y1	0x85
97462306a36Sopenharmony_ci		 * data[14] YAS537_OFFSET_Y2	0x86
97562306a36Sopenharmony_ci		 *
97662306a36Sopenharmony_ci		 * data[15] YAS537_HCK		0x88
97762306a36Sopenharmony_ci		 * data[16] YAS537_LCK		0x89
97862306a36Sopenharmony_ci		 */
97962306a36Sopenharmony_ci		for (i = 0; i < 12; i++) {
98062306a36Sopenharmony_ci			ret = regmap_write(yas5xx->map, YAS537_MTC + i,
98162306a36Sopenharmony_ci					   data[i]);
98262306a36Sopenharmony_ci			if (ret)
98362306a36Sopenharmony_ci				return ret;
98462306a36Sopenharmony_ci		}
98562306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
98662306a36Sopenharmony_ci			ret = regmap_write(yas5xx->map, YAS537_OFFSET_X + i,
98762306a36Sopenharmony_ci					   data[i + 12]);
98862306a36Sopenharmony_ci			if (ret)
98962306a36Sopenharmony_ci				return ret;
99062306a36Sopenharmony_ci			yas5xx->hard_offsets[i] = data[i + 12];
99162306a36Sopenharmony_ci		}
99262306a36Sopenharmony_ci		for (i = 0; i < 2; i++) {
99362306a36Sopenharmony_ci			ret = regmap_write(yas5xx->map, YAS537_HCK + i,
99462306a36Sopenharmony_ci					   data[i + 15]);
99562306a36Sopenharmony_ci			if (ret)
99662306a36Sopenharmony_ci				return ret;
99762306a36Sopenharmony_ci		}
99862306a36Sopenharmony_ci		break;
99962306a36Sopenharmony_ci	case YAS537_VERSION_1:
100062306a36Sopenharmony_ci		/*
100162306a36Sopenharmony_ci		 * The second version writes some data into registers but also
100262306a36Sopenharmony_ci		 * extracts calibration coefficients.
100362306a36Sopenharmony_ci		 *
100462306a36Sopenharmony_ci		 * Registers being written:
100562306a36Sopenharmony_ci		 *
100662306a36Sopenharmony_ci		 * data[0]  YAS537_MTC			0x93
100762306a36Sopenharmony_ci		 * data[1]  YAS537_MTC+1		0x94
100862306a36Sopenharmony_ci		 * data[2]  YAS537_MTC+2		0x95
100962306a36Sopenharmony_ci		 * data[3]  YAS537_MTC+3 (partially)	0x96
101062306a36Sopenharmony_ci		 *
101162306a36Sopenharmony_ci		 * data[12] YAS537_OFFSET_X		0x84
101262306a36Sopenharmony_ci		 * data[13] YAS537_OFFSET_Y1		0x85
101362306a36Sopenharmony_ci		 * data[14] YAS537_OFFSET_Y2		0x86
101462306a36Sopenharmony_ci		 *
101562306a36Sopenharmony_ci		 * data[15] YAS537_HCK (partially)	0x88
101662306a36Sopenharmony_ci		 *          YAS537_LCK (partially)	0x89
101762306a36Sopenharmony_ci		 * data[16] YAS537_OC  (partially)	0x9e
101862306a36Sopenharmony_ci		 */
101962306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
102062306a36Sopenharmony_ci			ret = regmap_write(yas5xx->map, YAS537_MTC + i,
102162306a36Sopenharmony_ci					   data[i]);
102262306a36Sopenharmony_ci			if (ret)
102362306a36Sopenharmony_ci				return ret;
102462306a36Sopenharmony_ci		}
102562306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
102662306a36Sopenharmony_ci			ret = regmap_write(yas5xx->map, YAS537_OFFSET_X + i,
102762306a36Sopenharmony_ci					   data[i + 12]);
102862306a36Sopenharmony_ci			if (ret)
102962306a36Sopenharmony_ci				return ret;
103062306a36Sopenharmony_ci			yas5xx->hard_offsets[i] = data[i + 12];
103162306a36Sopenharmony_ci		}
103262306a36Sopenharmony_ci		/*
103362306a36Sopenharmony_ci		 * Visualization of partially taken data:
103462306a36Sopenharmony_ci		 *
103562306a36Sopenharmony_ci		 * data[3]       n 7 6 5 4 3 2 1 0
103662306a36Sopenharmony_ci		 * YAS537_MTC+3    x x x 1 0 0 0 0
103762306a36Sopenharmony_ci		 *
103862306a36Sopenharmony_ci		 * data[15]      n 7 6 5 4 3 2 1 0
103962306a36Sopenharmony_ci		 * YAS537_HCK      x x x x 0
104062306a36Sopenharmony_ci		 *
104162306a36Sopenharmony_ci		 * data[15]      n 7 6 5 4 3 2 1 0
104262306a36Sopenharmony_ci		 * YAS537_LCK              x x x x 0
104362306a36Sopenharmony_ci		 *
104462306a36Sopenharmony_ci		 * data[16]      n 7 6 5 4 3 2 1 0
104562306a36Sopenharmony_ci		 * YAS537_OC           x x x x x x
104662306a36Sopenharmony_ci		 */
104762306a36Sopenharmony_ci		ret = regmap_write(yas5xx->map, YAS537_MTC + 3,
104862306a36Sopenharmony_ci				   FIELD_PREP(YAS537_MTC3_MASK_PREP,
104962306a36Sopenharmony_ci				   FIELD_GET(YAS537_MTC3_MASK_GET, data[3])) |
105062306a36Sopenharmony_ci				   YAS537_MTC3_ADD_BIT);
105162306a36Sopenharmony_ci		if (ret)
105262306a36Sopenharmony_ci			return ret;
105362306a36Sopenharmony_ci		ret = regmap_write(yas5xx->map, YAS537_HCK,
105462306a36Sopenharmony_ci				   FIELD_PREP(YAS537_HCK_MASK_PREP,
105562306a36Sopenharmony_ci				   FIELD_GET(YAS537_HCK_MASK_GET, data[15])));
105662306a36Sopenharmony_ci		if (ret)
105762306a36Sopenharmony_ci			return ret;
105862306a36Sopenharmony_ci		ret = regmap_write(yas5xx->map, YAS537_LCK,
105962306a36Sopenharmony_ci				   FIELD_PREP(YAS537_LCK_MASK_PREP,
106062306a36Sopenharmony_ci				   FIELD_GET(YAS537_LCK_MASK_GET, data[15])));
106162306a36Sopenharmony_ci		if (ret)
106262306a36Sopenharmony_ci			return ret;
106362306a36Sopenharmony_ci		ret = regmap_write(yas5xx->map, YAS537_OC,
106462306a36Sopenharmony_ci				   FIELD_GET(YAS537_OC_MASK_GET, data[16]));
106562306a36Sopenharmony_ci		if (ret)
106662306a36Sopenharmony_ci			return ret;
106762306a36Sopenharmony_ci		/*
106862306a36Sopenharmony_ci		 * For data extraction, build some blocks. Four 32-bit blocks
106962306a36Sopenharmony_ci		 * look appropriate.
107062306a36Sopenharmony_ci		 *
107162306a36Sopenharmony_ci		 *            n    7  6  5  4  3  2  1  0
107262306a36Sopenharmony_ci		 *  data[0]   0 [ Cx Cx Cx Cx Cx Cx Cx Cx ] bits 31 .. 24
107362306a36Sopenharmony_ci		 *  data[1]   1 [ Cx C1 C1 C1 C1 C1 C1 C1 ] bits 23 .. 16
107462306a36Sopenharmony_ci		 *  data[2]   2 [ C1 C1 C2 C2 C2 C2 C2 C2 ] bits 15 .. 8
107562306a36Sopenharmony_ci		 *  data[3]   3 [ C2 C2 C2                ] bits  7 .. 0
107662306a36Sopenharmony_ci		 *
107762306a36Sopenharmony_ci		 *            n    7  6  5  4  3  2  1  0
107862306a36Sopenharmony_ci		 *  data[3]   0 [          a2 a2 a2 a2 a2 ] bits 31 .. 24
107962306a36Sopenharmony_ci		 *  data[4]   1 [ a2 a2 a3 a3 a3 a3 a3 a3 ] bits 23 .. 16
108062306a36Sopenharmony_ci		 *  data[5]   2 [ a3 a4 a4 a4 a4 a4 a4 a4 ] bits 15 .. 8
108162306a36Sopenharmony_ci		 *  data[6]   3 [ a4                      ] bits  7 .. 0
108262306a36Sopenharmony_ci		 *
108362306a36Sopenharmony_ci		 *            n    7  6  5  4  3  2  1  0
108462306a36Sopenharmony_ci		 *  data[6]   0 [    a5 a5 a5 a5 a5 a5 a5 ] bits 31 .. 24
108562306a36Sopenharmony_ci		 *  data[7]   1 [ a5 a5 a6 a6 a6 a6 a6 a6 ] bits 23 .. 16
108662306a36Sopenharmony_ci		 *  data[8]   2 [ a6 a7 a7 a7 a7 a7 a7 a7 ] bits 15 .. 8
108762306a36Sopenharmony_ci		 *  data[9]   3 [ a7                      ] bits  7 .. 0
108862306a36Sopenharmony_ci		 *
108962306a36Sopenharmony_ci		 *            n    7  6  5  4  3  2  1  0
109062306a36Sopenharmony_ci		 *  data[9]   0 [    a8 a8 a8 a8 a8 a8 a8 ] bits 31 .. 24
109162306a36Sopenharmony_ci		 *  data[10]  1 [ a9 a9 a9 a9 a9 a9 a9 a9 ] bits 23 .. 16
109262306a36Sopenharmony_ci		 *  data[11]  2 [ a9  k  k  k  k  k  k  k ] bits 15 .. 8
109362306a36Sopenharmony_ci		 *  data[12]  3 [                         ] bits  7 .. 0
109462306a36Sopenharmony_ci		 */
109562306a36Sopenharmony_ci		val1 = get_unaligned_be32(&data[0]);
109662306a36Sopenharmony_ci		val2 = get_unaligned_be32(&data[3]);
109762306a36Sopenharmony_ci		val3 = get_unaligned_be32(&data[6]);
109862306a36Sopenharmony_ci		val4 = get_unaligned_be32(&data[9]);
109962306a36Sopenharmony_ci		/* Extract calibration coefficients and modify */
110062306a36Sopenharmony_ci		c->Cx  = FIELD_GET(GENMASK(31, 23), val1) - 256;
110162306a36Sopenharmony_ci		c->Cy1 = FIELD_GET(GENMASK(22, 14), val1) - 256;
110262306a36Sopenharmony_ci		c->Cy2 = FIELD_GET(GENMASK(13,  5), val1) - 256;
110362306a36Sopenharmony_ci		c->a2  = FIELD_GET(GENMASK(28, 22), val2) -  64;
110462306a36Sopenharmony_ci		c->a3  = FIELD_GET(GENMASK(21, 15), val2) -  64;
110562306a36Sopenharmony_ci		c->a4  = FIELD_GET(GENMASK(14,  7), val2) - 128;
110662306a36Sopenharmony_ci		c->a5  = FIELD_GET(GENMASK(30, 22), val3) - 112;
110762306a36Sopenharmony_ci		c->a6  = FIELD_GET(GENMASK(21, 15), val3) -  64;
110862306a36Sopenharmony_ci		c->a7  = FIELD_GET(GENMASK(14,  7), val3) - 128;
110962306a36Sopenharmony_ci		c->a8  = FIELD_GET(GENMASK(30, 24), val4) -  64;
111062306a36Sopenharmony_ci		c->a9  = FIELD_GET(GENMASK(23, 15), val4) - 112;
111162306a36Sopenharmony_ci		c->k   = FIELD_GET(GENMASK(14,  8), val4);
111262306a36Sopenharmony_ci		break;
111362306a36Sopenharmony_ci	default:
111462306a36Sopenharmony_ci		dev_err(yas5xx->dev, "unknown version of YAS537\n");
111562306a36Sopenharmony_ci		return -EINVAL;
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	return 0;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci/* Used by YAS530, YAS532 and YAS533 */
112262306a36Sopenharmony_cistatic void yas530_dump_calibration(struct yas5xx *yas5xx)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	struct yas5xx_calibration *c = &yas5xx->calibration;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "f[] = [%d, %d, %d]\n",
112762306a36Sopenharmony_ci		c->f[0], c->f[1], c->f[2]);
112862306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "r[] = [%d, %d, %d]\n",
112962306a36Sopenharmony_ci		c->r[0], c->r[1], c->r[2]);
113062306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "Cx = %d\n", c->Cx);
113162306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "Cy1 = %d\n", c->Cy1);
113262306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "Cy2 = %d\n", c->Cy2);
113362306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "a2 = %d\n", c->a2);
113462306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "a3 = %d\n", c->a3);
113562306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "a4 = %d\n", c->a4);
113662306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "a5 = %d\n", c->a5);
113762306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "a6 = %d\n", c->a6);
113862306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "a7 = %d\n", c->a7);
113962306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "a8 = %d\n", c->a8);
114062306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "a9 = %d\n", c->a9);
114162306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "k = %d\n", c->k);
114262306a36Sopenharmony_ci	dev_dbg(yas5xx->dev, "dck = %d\n", c->dck);
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_cistatic void yas537_dump_calibration(struct yas5xx *yas5xx)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	struct yas5xx_calibration *c = &yas5xx->calibration;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	if (yas5xx->version == YAS537_VERSION_1) {
115062306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "Cx = %d\n", c->Cx);
115162306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "Cy1 = %d\n", c->Cy1);
115262306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "Cy2 = %d\n", c->Cy2);
115362306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "a2 = %d\n", c->a2);
115462306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "a3 = %d\n", c->a3);
115562306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "a4 = %d\n", c->a4);
115662306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "a5 = %d\n", c->a5);
115762306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "a6 = %d\n", c->a6);
115862306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "a7 = %d\n", c->a7);
115962306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "a8 = %d\n", c->a8);
116062306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "a9 = %d\n", c->a9);
116162306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "k = %d\n", c->k);
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci/* Used by YAS530, YAS532 and YAS533 */
116662306a36Sopenharmony_cistatic int yas530_set_offsets(struct yas5xx *yas5xx, s8 ox, s8 oy1, s8 oy2)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci	int ret;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS530_OFFSET_X, ox);
117162306a36Sopenharmony_ci	if (ret)
117262306a36Sopenharmony_ci		return ret;
117362306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS530_OFFSET_Y1, oy1);
117462306a36Sopenharmony_ci	if (ret)
117562306a36Sopenharmony_ci		return ret;
117662306a36Sopenharmony_ci	return regmap_write(yas5xx->map, YAS530_OFFSET_Y2, oy2);
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci/* Used by YAS530, YAS532 and YAS533 */
118062306a36Sopenharmony_cistatic s8 yas530_adjust_offset(s8 old, int bit, u16 center, u16 measure)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	if (measure > center)
118362306a36Sopenharmony_ci		return old + BIT(bit);
118462306a36Sopenharmony_ci	if (measure < center)
118562306a36Sopenharmony_ci		return old - BIT(bit);
118662306a36Sopenharmony_ci	return old;
118762306a36Sopenharmony_ci}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci/* Used by YAS530, YAS532 and YAS533 */
119062306a36Sopenharmony_cistatic int yas530_measure_offsets(struct yas5xx *yas5xx)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci = yas5xx->chip_info;
119362306a36Sopenharmony_ci	int ret;
119462306a36Sopenharmony_ci	u16 center;
119562306a36Sopenharmony_ci	u16 t, x, y1, y2;
119662306a36Sopenharmony_ci	s8 ox, oy1, oy2;
119762306a36Sopenharmony_ci	int i;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	/* Actuate the init coil and measure offsets */
120062306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS530_ACTUATE_INIT_COIL, 0);
120162306a36Sopenharmony_ci	if (ret)
120262306a36Sopenharmony_ci		return ret;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	/* When the initcoil is active this should be around the center */
120562306a36Sopenharmony_ci	switch (ci->devid) {
120662306a36Sopenharmony_ci	case YAS530_DEVICE_ID:
120762306a36Sopenharmony_ci		center = YAS530_DATA_CENTER;
120862306a36Sopenharmony_ci		break;
120962306a36Sopenharmony_ci	case YAS532_DEVICE_ID:
121062306a36Sopenharmony_ci		center = YAS532_DATA_CENTER;
121162306a36Sopenharmony_ci		break;
121262306a36Sopenharmony_ci	default:
121362306a36Sopenharmony_ci		dev_err(yas5xx->dev, "unknown device type\n");
121462306a36Sopenharmony_ci		return -EINVAL;
121562306a36Sopenharmony_ci	}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	/*
121862306a36Sopenharmony_ci	 * We set offsets in the interval +-31 by iterating
121962306a36Sopenharmony_ci	 * +-16, +-8, +-4, +-2, +-1 adjusting the offsets each
122062306a36Sopenharmony_ci	 * time, then writing the final offsets into the
122162306a36Sopenharmony_ci	 * registers.
122262306a36Sopenharmony_ci	 *
122362306a36Sopenharmony_ci	 * NOTE: these offsets are NOT in the same unit or magnitude
122462306a36Sopenharmony_ci	 * as the values for [x, y1, y2]. The value is +/-31
122562306a36Sopenharmony_ci	 * but the effect on the raw values is much larger.
122662306a36Sopenharmony_ci	 * The effect of the offset is to bring the measure
122762306a36Sopenharmony_ci	 * rougly to the center.
122862306a36Sopenharmony_ci	 */
122962306a36Sopenharmony_ci	ox = 0;
123062306a36Sopenharmony_ci	oy1 = 0;
123162306a36Sopenharmony_ci	oy2 = 0;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	for (i = 4; i >= 0; i--) {
123462306a36Sopenharmony_ci		ret = yas530_set_offsets(yas5xx, ox, oy1, oy2);
123562306a36Sopenharmony_ci		if (ret)
123662306a36Sopenharmony_ci			return ret;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci		ret = yas530_measure(yas5xx, &t, &x, &y1, &y2);
123962306a36Sopenharmony_ci		if (ret)
124062306a36Sopenharmony_ci			return ret;
124162306a36Sopenharmony_ci		dev_dbg(yas5xx->dev, "measurement %d: x=%d, y1=%d, y2=%d\n",
124262306a36Sopenharmony_ci			5-i, x, y1, y2);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci		ox = yas530_adjust_offset(ox, i, center, x);
124562306a36Sopenharmony_ci		oy1 = yas530_adjust_offset(oy1, i, center, y1);
124662306a36Sopenharmony_ci		oy2 = yas530_adjust_offset(oy2, i, center, y2);
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/* Needed for calibration algorithm */
125062306a36Sopenharmony_ci	yas5xx->hard_offsets[0] = ox;
125162306a36Sopenharmony_ci	yas5xx->hard_offsets[1] = oy1;
125262306a36Sopenharmony_ci	yas5xx->hard_offsets[2] = oy2;
125362306a36Sopenharmony_ci	ret = yas530_set_offsets(yas5xx, ox, oy1, oy2);
125462306a36Sopenharmony_ci	if (ret)
125562306a36Sopenharmony_ci		return ret;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	dev_info(yas5xx->dev, "discovered hard offsets: x=%d, y1=%d, y2=%d\n",
125862306a36Sopenharmony_ci		 ox, oy1, oy2);
125962306a36Sopenharmony_ci	return 0;
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci/* Used by YAS530, YAS532 and YAS533 */
126362306a36Sopenharmony_cistatic int yas530_power_on(struct yas5xx *yas5xx)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	unsigned int val;
126662306a36Sopenharmony_ci	int ret;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	/* Zero the test registers */
126962306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS530_TEST1, 0);
127062306a36Sopenharmony_ci	if (ret)
127162306a36Sopenharmony_ci		return ret;
127262306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS530_TEST2, 0);
127362306a36Sopenharmony_ci	if (ret)
127462306a36Sopenharmony_ci		return ret;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/* Set up for no interrupts, calibrated clock divider */
127762306a36Sopenharmony_ci	val = FIELD_PREP(YAS5XX_CONFIG_CCK_MASK, yas5xx->calibration.dck);
127862306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS530_CONFIG, val);
127962306a36Sopenharmony_ci	if (ret)
128062306a36Sopenharmony_ci		return ret;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	/* Measure interval 0 (back-to-back?)  */
128362306a36Sopenharmony_ci	return regmap_write(yas5xx->map, YAS530_MEASURE_INTERVAL, 0);
128462306a36Sopenharmony_ci}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_cistatic int yas537_power_on(struct yas5xx *yas5xx)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	__be16 buf;
128962306a36Sopenharmony_ci	int ret;
129062306a36Sopenharmony_ci	u8 intrvl;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	/* Writing ADCCAL and TRM registers */
129362306a36Sopenharmony_ci	buf = cpu_to_be16(GENMASK(9, 3));
129462306a36Sopenharmony_ci	ret = regmap_bulk_write(yas5xx->map, YAS537_ADCCAL, &buf, sizeof(buf));
129562306a36Sopenharmony_ci	if (ret)
129662306a36Sopenharmony_ci		return ret;
129762306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS537_TRM, GENMASK(7, 0));
129862306a36Sopenharmony_ci	if (ret)
129962306a36Sopenharmony_ci		return ret;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	/* The interval value is static in regular operation */
130262306a36Sopenharmony_ci	intrvl = (YAS537_DEFAULT_SENSOR_DELAY_MS * MILLI
130362306a36Sopenharmony_ci		 - YAS537_MEASURE_TIME_WORST_US) / 4100;
130462306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS537_MEASURE_INTERVAL, intrvl);
130562306a36Sopenharmony_ci	if (ret)
130662306a36Sopenharmony_ci		return ret;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	/* The average value is also static in regular operation */
130962306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS537_AVR, YAS537_MAG_AVERAGE_32_MASK);
131062306a36Sopenharmony_ci	if (ret)
131162306a36Sopenharmony_ci		return ret;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	/* Perform the "rcoil" part but skip the "last_after_rcoil" read */
131462306a36Sopenharmony_ci	ret = regmap_write(yas5xx->map, YAS537_CONFIG, BIT(3));
131562306a36Sopenharmony_ci	if (ret)
131662306a36Sopenharmony_ci		return ret;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	/* Wait until the coil has ramped up */
131962306a36Sopenharmony_ci	usleep_range(YAS537_MAG_RCOIL_TIME_US, YAS537_MAG_RCOIL_TIME_US + 100);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	return 0;
132262306a36Sopenharmony_ci}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_cistatic const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
132562306a36Sopenharmony_ci	[yas530] = {
132662306a36Sopenharmony_ci		.devid = YAS530_DEVICE_ID,
132762306a36Sopenharmony_ci		.product_name = "YAS530 MS-3E",
132862306a36Sopenharmony_ci		.version_names = { "A", "B" },
132962306a36Sopenharmony_ci		.volatile_reg = yas530_volatile_reg,
133062306a36Sopenharmony_ci		.volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
133162306a36Sopenharmony_ci		.scaling_val2 = 100000000, /* picotesla to Gauss */
133262306a36Sopenharmony_ci		.t_ref = 182, /* counts */
133362306a36Sopenharmony_ci		.min_temp_x10 = -620, /* 1/10:s degrees Celsius */
133462306a36Sopenharmony_ci		.get_measure = yas530_get_measure,
133562306a36Sopenharmony_ci		.get_calibration_data = yas530_get_calibration_data,
133662306a36Sopenharmony_ci		.dump_calibration = yas530_dump_calibration,
133762306a36Sopenharmony_ci		.measure_offsets = yas530_measure_offsets,
133862306a36Sopenharmony_ci		.power_on = yas530_power_on,
133962306a36Sopenharmony_ci	},
134062306a36Sopenharmony_ci	[yas532] = {
134162306a36Sopenharmony_ci		.devid = YAS532_DEVICE_ID,
134262306a36Sopenharmony_ci		.product_name = "YAS532 MS-3R",
134362306a36Sopenharmony_ci		.version_names = { "AB", "AC" },
134462306a36Sopenharmony_ci		.volatile_reg = yas530_volatile_reg,
134562306a36Sopenharmony_ci		.volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
134662306a36Sopenharmony_ci		.scaling_val2 = 100000, /* nanotesla to Gauss */
134762306a36Sopenharmony_ci		.t_ref = 390, /* counts */
134862306a36Sopenharmony_ci		.min_temp_x10 = -500, /* 1/10:s degrees Celsius */
134962306a36Sopenharmony_ci		.get_measure = yas530_get_measure,
135062306a36Sopenharmony_ci		.get_calibration_data = yas532_get_calibration_data,
135162306a36Sopenharmony_ci		.dump_calibration = yas530_dump_calibration,
135262306a36Sopenharmony_ci		.measure_offsets = yas530_measure_offsets,
135362306a36Sopenharmony_ci		.power_on = yas530_power_on,
135462306a36Sopenharmony_ci	},
135562306a36Sopenharmony_ci	[yas533] = {
135662306a36Sopenharmony_ci		.devid = YAS532_DEVICE_ID,
135762306a36Sopenharmony_ci		.product_name = "YAS533 MS-3F",
135862306a36Sopenharmony_ci		.version_names = { "AB", "AC" },
135962306a36Sopenharmony_ci		.volatile_reg = yas530_volatile_reg,
136062306a36Sopenharmony_ci		.volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
136162306a36Sopenharmony_ci		.scaling_val2 = 100000, /* nanotesla to Gauss */
136262306a36Sopenharmony_ci		.t_ref = 390, /* counts */
136362306a36Sopenharmony_ci		.min_temp_x10 = -500, /* 1/10:s degrees Celsius */
136462306a36Sopenharmony_ci		.get_measure = yas530_get_measure,
136562306a36Sopenharmony_ci		.get_calibration_data = yas532_get_calibration_data,
136662306a36Sopenharmony_ci		.dump_calibration = yas530_dump_calibration,
136762306a36Sopenharmony_ci		.measure_offsets = yas530_measure_offsets,
136862306a36Sopenharmony_ci		.power_on = yas530_power_on,
136962306a36Sopenharmony_ci	},
137062306a36Sopenharmony_ci	[yas537] = {
137162306a36Sopenharmony_ci		.devid = YAS537_DEVICE_ID,
137262306a36Sopenharmony_ci		.product_name = "YAS537 MS-3T",
137362306a36Sopenharmony_ci		.version_names = { "v0", "v1" }, /* version naming unknown */
137462306a36Sopenharmony_ci		.volatile_reg = yas537_volatile_reg,
137562306a36Sopenharmony_ci		.volatile_reg_qty = ARRAY_SIZE(yas537_volatile_reg),
137662306a36Sopenharmony_ci		.scaling_val2 = 100000, /* nanotesla to Gauss */
137762306a36Sopenharmony_ci		.t_ref = 8120, /* counts */
137862306a36Sopenharmony_ci		.min_temp_x10 = -3860, /* 1/10:s degrees Celsius */
137962306a36Sopenharmony_ci		.get_measure = yas537_get_measure,
138062306a36Sopenharmony_ci		.get_calibration_data = yas537_get_calibration_data,
138162306a36Sopenharmony_ci		.dump_calibration = yas537_dump_calibration,
138262306a36Sopenharmony_ci		/* .measure_offets is not needed for yas537 */
138362306a36Sopenharmony_ci		.power_on = yas537_power_on,
138462306a36Sopenharmony_ci	},
138562306a36Sopenharmony_ci};
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_cistatic int yas5xx_probe(struct i2c_client *i2c)
138862306a36Sopenharmony_ci{
138962306a36Sopenharmony_ci	const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
139062306a36Sopenharmony_ci	struct iio_dev *indio_dev;
139162306a36Sopenharmony_ci	struct device *dev = &i2c->dev;
139262306a36Sopenharmony_ci	struct yas5xx *yas5xx;
139362306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci;
139462306a36Sopenharmony_ci	int id_check;
139562306a36Sopenharmony_ci	int ret;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(dev, sizeof(*yas5xx));
139862306a36Sopenharmony_ci	if (!indio_dev)
139962306a36Sopenharmony_ci		return -ENOMEM;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	yas5xx = iio_priv(indio_dev);
140262306a36Sopenharmony_ci	i2c_set_clientdata(i2c, indio_dev);
140362306a36Sopenharmony_ci	yas5xx->dev = dev;
140462306a36Sopenharmony_ci	mutex_init(&yas5xx->lock);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	ret = iio_read_mount_matrix(dev, &yas5xx->orientation);
140762306a36Sopenharmony_ci	if (ret)
140862306a36Sopenharmony_ci		return ret;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	yas5xx->regs[0].supply = "vdd";
141162306a36Sopenharmony_ci	yas5xx->regs[1].supply = "iovdd";
141262306a36Sopenharmony_ci	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(yas5xx->regs),
141362306a36Sopenharmony_ci				      yas5xx->regs);
141462306a36Sopenharmony_ci	if (ret)
141562306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "cannot get regulators\n");
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	ret = regulator_bulk_enable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
141862306a36Sopenharmony_ci	if (ret)
141962306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "cannot enable regulators\n");
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	/* See comment in runtime resume callback */
142262306a36Sopenharmony_ci	usleep_range(31000, 40000);
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	/* This will take the device out of reset if need be */
142562306a36Sopenharmony_ci	yas5xx->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
142662306a36Sopenharmony_ci	if (IS_ERR(yas5xx->reset)) {
142762306a36Sopenharmony_ci		ret = dev_err_probe(dev, PTR_ERR(yas5xx->reset), "failed to get reset line\n");
142862306a36Sopenharmony_ci		goto reg_off;
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	yas5xx->map = devm_regmap_init_i2c(i2c, &yas5xx_regmap_config);
143262306a36Sopenharmony_ci	if (IS_ERR(yas5xx->map)) {
143362306a36Sopenharmony_ci		ret = dev_err_probe(dev, PTR_ERR(yas5xx->map), "failed to allocate register map\n");
143462306a36Sopenharmony_ci		goto assert_reset;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	ci = device_get_match_data(dev);
143862306a36Sopenharmony_ci	if (!ci)
143962306a36Sopenharmony_ci		ci = (const struct yas5xx_chip_info *)id->driver_data;
144062306a36Sopenharmony_ci	yas5xx->chip_info = ci;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check);
144362306a36Sopenharmony_ci	if (ret)
144462306a36Sopenharmony_ci		goto assert_reset;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if (id_check != ci->devid) {
144762306a36Sopenharmony_ci		ret = dev_err_probe(dev, -ENODEV,
144862306a36Sopenharmony_ci				    "device ID %02x doesn't match %s\n",
144962306a36Sopenharmony_ci				    id_check, id->name);
145062306a36Sopenharmony_ci		goto assert_reset;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	ret = ci->get_calibration_data(yas5xx);
145462306a36Sopenharmony_ci	if (ret)
145562306a36Sopenharmony_ci		goto assert_reset;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	dev_info(dev, "detected %s %s\n", ci->product_name,
145862306a36Sopenharmony_ci		 ci->version_names[yas5xx->version]);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	ci->dump_calibration(yas5xx);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	ret = ci->power_on(yas5xx);
146362306a36Sopenharmony_ci	if (ret)
146462306a36Sopenharmony_ci		goto assert_reset;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	if (ci->measure_offsets) {
146762306a36Sopenharmony_ci		ret = ci->measure_offsets(yas5xx);
146862306a36Sopenharmony_ci		if (ret)
146962306a36Sopenharmony_ci			goto assert_reset;
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	indio_dev->info = &yas5xx_info;
147362306a36Sopenharmony_ci	indio_dev->available_scan_masks = yas5xx_scan_masks;
147462306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
147562306a36Sopenharmony_ci	indio_dev->name = id->name;
147662306a36Sopenharmony_ci	indio_dev->channels = yas5xx_channels;
147762306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(yas5xx_channels);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	ret = iio_triggered_buffer_setup(indio_dev, NULL,
148062306a36Sopenharmony_ci					 yas5xx_handle_trigger,
148162306a36Sopenharmony_ci					 NULL);
148262306a36Sopenharmony_ci	if (ret) {
148362306a36Sopenharmony_ci		dev_err_probe(dev, ret, "triggered buffer setup failed\n");
148462306a36Sopenharmony_ci		goto assert_reset;
148562306a36Sopenharmony_ci	}
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	ret = iio_device_register(indio_dev);
148862306a36Sopenharmony_ci	if (ret) {
148962306a36Sopenharmony_ci		dev_err_probe(dev, ret, "device register failed\n");
149062306a36Sopenharmony_ci		goto cleanup_buffer;
149162306a36Sopenharmony_ci	}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	/* Take runtime PM online */
149462306a36Sopenharmony_ci	pm_runtime_get_noresume(dev);
149562306a36Sopenharmony_ci	pm_runtime_set_active(dev);
149662306a36Sopenharmony_ci	pm_runtime_enable(dev);
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, YAS5XX_AUTOSUSPEND_DELAY_MS);
149962306a36Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
150062306a36Sopenharmony_ci	pm_runtime_put(dev);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	return 0;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_cicleanup_buffer:
150562306a36Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
150662306a36Sopenharmony_ciassert_reset:
150762306a36Sopenharmony_ci	gpiod_set_value_cansleep(yas5xx->reset, 1);
150862306a36Sopenharmony_cireg_off:
150962306a36Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	return ret;
151262306a36Sopenharmony_ci}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_cistatic void yas5xx_remove(struct i2c_client *i2c)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(i2c);
151762306a36Sopenharmony_ci	struct yas5xx *yas5xx = iio_priv(indio_dev);
151862306a36Sopenharmony_ci	struct device *dev = &i2c->dev;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
152162306a36Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
152262306a36Sopenharmony_ci	/*
152362306a36Sopenharmony_ci	 * Now we can't get any more reads from the device, which would
152462306a36Sopenharmony_ci	 * also call pm_runtime* functions and race with our disable
152562306a36Sopenharmony_ci	 * code. Disable PM runtime in orderly fashion and power down.
152662306a36Sopenharmony_ci	 */
152762306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
152862306a36Sopenharmony_ci	pm_runtime_put_noidle(dev);
152962306a36Sopenharmony_ci	pm_runtime_disable(dev);
153062306a36Sopenharmony_ci	gpiod_set_value_cansleep(yas5xx->reset, 1);
153162306a36Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
153262306a36Sopenharmony_ci}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_cistatic int yas5xx_runtime_suspend(struct device *dev)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
153762306a36Sopenharmony_ci	struct yas5xx *yas5xx = iio_priv(indio_dev);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	gpiod_set_value_cansleep(yas5xx->reset, 1);
154062306a36Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	return 0;
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_cistatic int yas5xx_runtime_resume(struct device *dev)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
154862306a36Sopenharmony_ci	struct yas5xx *yas5xx = iio_priv(indio_dev);
154962306a36Sopenharmony_ci	const struct yas5xx_chip_info *ci = yas5xx->chip_info;
155062306a36Sopenharmony_ci	int ret;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	ret = regulator_bulk_enable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
155362306a36Sopenharmony_ci	if (ret) {
155462306a36Sopenharmony_ci		dev_err(dev, "cannot enable regulators\n");
155562306a36Sopenharmony_ci		return ret;
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	/*
155962306a36Sopenharmony_ci	 * The YAS530 datasheet says TVSKW is up to 30 ms, after that 1 ms
156062306a36Sopenharmony_ci	 * for all voltages to settle. The YAS532 is 10ms then 4ms for the
156162306a36Sopenharmony_ci	 * I2C to come online. Let's keep it safe and put this at 31ms.
156262306a36Sopenharmony_ci	 */
156362306a36Sopenharmony_ci	usleep_range(31000, 40000);
156462306a36Sopenharmony_ci	gpiod_set_value_cansleep(yas5xx->reset, 0);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	ret = ci->power_on(yas5xx);
156762306a36Sopenharmony_ci	if (ret) {
156862306a36Sopenharmony_ci		dev_err(dev, "cannot power on\n");
156962306a36Sopenharmony_ci		goto out_reset;
157062306a36Sopenharmony_ci	}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	return 0;
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ciout_reset:
157562306a36Sopenharmony_ci	gpiod_set_value_cansleep(yas5xx->reset, 1);
157662306a36Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	return ret;
157962306a36Sopenharmony_ci}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cistatic DEFINE_RUNTIME_DEV_PM_OPS(yas5xx_dev_pm_ops, yas5xx_runtime_suspend,
158262306a36Sopenharmony_ci				 yas5xx_runtime_resume, NULL);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_cistatic const struct i2c_device_id yas5xx_id[] = {
158562306a36Sopenharmony_ci	{"yas530", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas530] },
158662306a36Sopenharmony_ci	{"yas532", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] },
158762306a36Sopenharmony_ci	{"yas533", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] },
158862306a36Sopenharmony_ci	{"yas537", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] },
158962306a36Sopenharmony_ci	{}
159062306a36Sopenharmony_ci};
159162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, yas5xx_id);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_cistatic const struct of_device_id yas5xx_of_match[] = {
159462306a36Sopenharmony_ci	{ .compatible = "yamaha,yas530", &yas5xx_chip_info_tbl[yas530] },
159562306a36Sopenharmony_ci	{ .compatible = "yamaha,yas532", &yas5xx_chip_info_tbl[yas532] },
159662306a36Sopenharmony_ci	{ .compatible = "yamaha,yas533", &yas5xx_chip_info_tbl[yas533] },
159762306a36Sopenharmony_ci	{ .compatible = "yamaha,yas537", &yas5xx_chip_info_tbl[yas537] },
159862306a36Sopenharmony_ci	{}
159962306a36Sopenharmony_ci};
160062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, yas5xx_of_match);
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_cistatic struct i2c_driver yas5xx_driver = {
160362306a36Sopenharmony_ci	.driver	 = {
160462306a36Sopenharmony_ci		.name	= "yas5xx",
160562306a36Sopenharmony_ci		.of_match_table = yas5xx_of_match,
160662306a36Sopenharmony_ci		.pm = pm_ptr(&yas5xx_dev_pm_ops),
160762306a36Sopenharmony_ci	},
160862306a36Sopenharmony_ci	.probe = yas5xx_probe,
160962306a36Sopenharmony_ci	.remove	  = yas5xx_remove,
161062306a36Sopenharmony_ci	.id_table = yas5xx_id,
161162306a36Sopenharmony_ci};
161262306a36Sopenharmony_cimodule_i2c_driver(yas5xx_driver);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ciMODULE_DESCRIPTION("Yamaha YAS53x 3-axis magnetometer driver");
161562306a36Sopenharmony_ciMODULE_AUTHOR("Linus Walleij");
161662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1617