xref: /openbmc/linux/drivers/iio/magnetometer/yamaha-yas530.c (revision bb354aeb364f9dee51e16edfdf6194ce4ba9237e)
1de8860b1SLinus Walleij // SPDX-License-Identifier: GPL-2.0-only
2de8860b1SLinus Walleij /*
3de8860b1SLinus Walleij  * Driver for the Yamaha YAS magnetic sensors, often used in Samsung
4de8860b1SLinus Walleij  * mobile phones. While all are not yet handled because of lacking
5de8860b1SLinus Walleij  * hardware, expand this driver to handle the different variants:
6de8860b1SLinus Walleij  *
7de8860b1SLinus Walleij  * YAS530 MS-3E (2011 Samsung Galaxy S Advance)
8de8860b1SLinus Walleij  * YAS532 MS-3R (2011 Samsung Galaxy S4)
9de8860b1SLinus Walleij  * YAS533 MS-3F (Vivo 1633, 1707, V3, Y21L)
10de8860b1SLinus Walleij  * (YAS534 is a magnetic switch, not handled)
11de8860b1SLinus Walleij  * YAS535 MS-6C
12de8860b1SLinus Walleij  * YAS536 MS-3W
13de8860b1SLinus Walleij  * YAS537 MS-3T (2015 Samsung Galaxy S6, Note 5, Xiaomi)
14de8860b1SLinus Walleij  * YAS539 MS-3S (2018 Samsung Galaxy A7 SM-A750FN)
15de8860b1SLinus Walleij  *
16de8860b1SLinus Walleij  * Code functions found in the MPU3050 YAS530 and YAS532 drivers
17de8860b1SLinus Walleij  * named "inv_compass" in the Tegra Android kernel tree.
18de8860b1SLinus Walleij  * Copyright (C) 2012 InvenSense Corporation
19de8860b1SLinus Walleij  *
20de8860b1SLinus Walleij  * Author: Linus Walleij <linus.walleij@linaro.org>
21de8860b1SLinus Walleij  */
22de8860b1SLinus Walleij #include <linux/bitfield.h>
23de8860b1SLinus Walleij #include <linux/bitops.h>
24de8860b1SLinus Walleij #include <linux/delay.h>
25de8860b1SLinus Walleij #include <linux/err.h>
26de8860b1SLinus Walleij #include <linux/gpio/consumer.h>
27de8860b1SLinus Walleij #include <linux/i2c.h>
28de8860b1SLinus Walleij #include <linux/module.h>
29de8860b1SLinus Walleij #include <linux/mod_devicetable.h>
30de8860b1SLinus Walleij #include <linux/mutex.h>
31de8860b1SLinus Walleij #include <linux/pm_runtime.h>
32de8860b1SLinus Walleij #include <linux/regmap.h>
33de8860b1SLinus Walleij #include <linux/regulator/consumer.h>
34de8860b1SLinus Walleij #include <linux/random.h>
35de8860b1SLinus Walleij 
36de8860b1SLinus Walleij #include <linux/iio/buffer.h>
37de8860b1SLinus Walleij #include <linux/iio/iio.h>
38de8860b1SLinus Walleij #include <linux/iio/trigger_consumer.h>
39de8860b1SLinus Walleij #include <linux/iio/triggered_buffer.h>
40de8860b1SLinus Walleij 
41*bb354aebSLinus Walleij #include <asm/unaligned.h>
42*bb354aebSLinus Walleij 
43de8860b1SLinus Walleij /* This register map covers YAS530 and YAS532 but differs in YAS 537 and YAS539 */
44de8860b1SLinus Walleij #define YAS5XX_DEVICE_ID		0x80
45de8860b1SLinus Walleij #define YAS5XX_ACTUATE_INIT_COIL	0x81
46de8860b1SLinus Walleij #define YAS5XX_MEASURE			0x82
47de8860b1SLinus Walleij #define YAS5XX_CONFIG			0x83
48de8860b1SLinus Walleij #define YAS5XX_MEASURE_INTERVAL		0x84
49de8860b1SLinus Walleij #define YAS5XX_OFFSET_X			0x85 /* [-31 .. 31] */
50de8860b1SLinus Walleij #define YAS5XX_OFFSET_Y1		0x86 /* [-31 .. 31] */
51de8860b1SLinus Walleij #define YAS5XX_OFFSET_Y2		0x87 /* [-31 .. 31] */
52de8860b1SLinus Walleij #define YAS5XX_TEST1			0x88
53de8860b1SLinus Walleij #define YAS5XX_TEST2			0x89
54de8860b1SLinus Walleij #define YAS5XX_CAL			0x90
55de8860b1SLinus Walleij #define YAS5XX_MEASURE_DATA		0xB0
56de8860b1SLinus Walleij 
57de8860b1SLinus Walleij /* Bits in the YAS5xx config register */
58de8860b1SLinus Walleij #define YAS5XX_CONFIG_INTON		BIT(0) /* Interrupt on? */
59de8860b1SLinus Walleij #define YAS5XX_CONFIG_INTHACT		BIT(1) /* Interrupt active high? */
60de8860b1SLinus Walleij #define YAS5XX_CONFIG_CCK_MASK		GENMASK(4, 2)
61de8860b1SLinus Walleij #define YAS5XX_CONFIG_CCK_SHIFT		2
62de8860b1SLinus Walleij 
63de8860b1SLinus Walleij /* Bits in the measure command register */
64de8860b1SLinus Walleij #define YAS5XX_MEASURE_START		BIT(0)
65de8860b1SLinus Walleij #define YAS5XX_MEASURE_LDTC		BIT(1)
66de8860b1SLinus Walleij #define YAS5XX_MEASURE_FORS		BIT(2)
67de8860b1SLinus Walleij #define YAS5XX_MEASURE_DLYMES		BIT(4)
68de8860b1SLinus Walleij 
69de8860b1SLinus Walleij /* Bits in the measure data register */
70de8860b1SLinus Walleij #define YAS5XX_MEASURE_DATA_BUSY	BIT(7)
71de8860b1SLinus Walleij 
72de8860b1SLinus Walleij #define YAS530_DEVICE_ID		0x01 /* YAS530 (MS-3E) */
73de8860b1SLinus Walleij #define YAS530_VERSION_A		0 /* YAS530 (MS-3E A) */
74de8860b1SLinus Walleij #define YAS530_VERSION_B		1 /* YAS530B (MS-3E B) */
75de8860b1SLinus Walleij #define YAS530_VERSION_A_COEF		380
76de8860b1SLinus Walleij #define YAS530_VERSION_B_COEF		550
77de8860b1SLinus Walleij #define YAS530_DATA_BITS		12
78de8860b1SLinus Walleij #define YAS530_DATA_CENTER		BIT(YAS530_DATA_BITS - 1)
79de8860b1SLinus Walleij #define YAS530_DATA_OVERFLOW		(BIT(YAS530_DATA_BITS) - 1)
80de8860b1SLinus Walleij 
81de8860b1SLinus Walleij #define YAS532_DEVICE_ID		0x02 /* YAS532/YAS533 (MS-3R/F) */
82de8860b1SLinus Walleij #define YAS532_VERSION_AB		0 /* YAS532/533 AB (MS-3R/F AB) */
83de8860b1SLinus Walleij #define YAS532_VERSION_AC		1 /* YAS532/533 AC (MS-3R/F AC) */
84de8860b1SLinus Walleij #define YAS532_VERSION_AB_COEF		1800
85de8860b1SLinus Walleij #define YAS532_VERSION_AC_COEF_X	850
86de8860b1SLinus Walleij #define YAS532_VERSION_AC_COEF_Y1	750
87de8860b1SLinus Walleij #define YAS532_VERSION_AC_COEF_Y2	750
88de8860b1SLinus Walleij #define YAS532_DATA_BITS		13
89de8860b1SLinus Walleij #define YAS532_DATA_CENTER		BIT(YAS532_DATA_BITS - 1)
90de8860b1SLinus Walleij #define YAS532_DATA_OVERFLOW		(BIT(YAS532_DATA_BITS) - 1)
91de8860b1SLinus Walleij #define YAS532_20DEGREES		390 /* Looks like Kelvin */
92de8860b1SLinus Walleij 
93de8860b1SLinus Walleij /* These variant IDs are known from code dumps */
94de8860b1SLinus Walleij #define YAS537_DEVICE_ID		0x07 /* YAS537 (MS-3T) */
95de8860b1SLinus Walleij #define YAS539_DEVICE_ID		0x08 /* YAS539 (MS-3S) */
96de8860b1SLinus Walleij 
97de8860b1SLinus Walleij /* Turn off device regulators etc after 5 seconds of inactivity */
98de8860b1SLinus Walleij #define YAS5XX_AUTOSUSPEND_DELAY_MS	5000
99de8860b1SLinus Walleij 
100de8860b1SLinus Walleij struct yas5xx_calibration {
101de8860b1SLinus Walleij 	/* Linearization calibration x, y1, y2 */
102de8860b1SLinus Walleij 	s32 r[3];
103de8860b1SLinus Walleij 	u32 f[3];
104de8860b1SLinus Walleij 	/* Temperature compensation calibration */
105de8860b1SLinus Walleij 	s32 Cx, Cy1, Cy2;
106de8860b1SLinus Walleij 	/* Misc calibration coefficients */
107de8860b1SLinus Walleij 	s32 a2, a3, a4, a5, a6, a7, a8, a9, k;
108de8860b1SLinus Walleij 	/* clock divider */
109de8860b1SLinus Walleij 	u8 dck;
110de8860b1SLinus Walleij };
111de8860b1SLinus Walleij 
112de8860b1SLinus Walleij /**
113de8860b1SLinus Walleij  * struct yas5xx - state container for the YAS5xx driver
114de8860b1SLinus Walleij  * @dev: parent device pointer
115de8860b1SLinus Walleij  * @devid: device ID number
116de8860b1SLinus Walleij  * @version: device version
117de8860b1SLinus Walleij  * @name: device name
118de8860b1SLinus Walleij  * @calibration: calibration settings from the OTP storage
119de8860b1SLinus Walleij  * @hard_offsets: offsets for each axis measured with initcoil actuated
120de8860b1SLinus Walleij  * @orientation: mounting matrix, flipped axis etc
121de8860b1SLinus Walleij  * @map: regmap to access the YAX5xx registers over I2C
122de8860b1SLinus Walleij  * @regs: the vdd and vddio power regulators
123de8860b1SLinus Walleij  * @reset: optional GPIO line used for handling RESET
124de8860b1SLinus Walleij  * @lock: locks the magnetometer for exclusive use during a measurement (which
125de8860b1SLinus Walleij  * involves several register transactions so the regmap lock is not enough)
126de8860b1SLinus Walleij  * so that measurements get serialized in a first-come-first serve manner
127de8860b1SLinus Walleij  * @scan: naturally aligned measurements
128de8860b1SLinus Walleij  */
129de8860b1SLinus Walleij struct yas5xx {
130de8860b1SLinus Walleij 	struct device *dev;
131de8860b1SLinus Walleij 	unsigned int devid;
132de8860b1SLinus Walleij 	unsigned int version;
133de8860b1SLinus Walleij 	char name[16];
134de8860b1SLinus Walleij 	struct yas5xx_calibration calibration;
135de8860b1SLinus Walleij 	u8 hard_offsets[3];
136de8860b1SLinus Walleij 	struct iio_mount_matrix orientation;
137de8860b1SLinus Walleij 	struct regmap *map;
138de8860b1SLinus Walleij 	struct regulator_bulk_data regs[2];
139de8860b1SLinus Walleij 	struct gpio_desc *reset;
140de8860b1SLinus Walleij 	struct mutex lock;
141de8860b1SLinus Walleij 	/*
142de8860b1SLinus Walleij 	 * The scanout is 4 x 32 bits in CPU endianness.
143de8860b1SLinus Walleij 	 * Ensure timestamp is naturally aligned
144de8860b1SLinus Walleij 	 */
145de8860b1SLinus Walleij 	struct {
146de8860b1SLinus Walleij 		s32 channels[4];
147de8860b1SLinus Walleij 		s64 ts __aligned(8);
148de8860b1SLinus Walleij 	} scan;
149de8860b1SLinus Walleij };
150de8860b1SLinus Walleij 
151de8860b1SLinus Walleij /* On YAS530 the x, y1 and y2 values are 12 bits */
152de8860b1SLinus Walleij static u16 yas530_extract_axis(u8 *data)
153de8860b1SLinus Walleij {
154de8860b1SLinus Walleij 	u16 val;
155de8860b1SLinus Walleij 
156de8860b1SLinus Walleij 	/*
157de8860b1SLinus Walleij 	 * These are the bits used in a 16bit word:
158de8860b1SLinus Walleij 	 * 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
159de8860b1SLinus Walleij 	 *    x  x  x  x  x  x  x  x  x  x  x  x
160de8860b1SLinus Walleij 	 */
161de8860b1SLinus Walleij 	val = get_unaligned_be16(&data[0]);
162de8860b1SLinus Walleij 	val = FIELD_GET(GENMASK(14, 3), val);
163de8860b1SLinus Walleij 	return val;
164de8860b1SLinus Walleij }
165de8860b1SLinus Walleij 
166de8860b1SLinus Walleij /* On YAS532 the x, y1 and y2 values are 13 bits */
167de8860b1SLinus Walleij static u16 yas532_extract_axis(u8 *data)
168de8860b1SLinus Walleij {
169de8860b1SLinus Walleij 	u16 val;
170de8860b1SLinus Walleij 
171de8860b1SLinus Walleij 	/*
172de8860b1SLinus Walleij 	 * These are the bits used in a 16bit word:
173de8860b1SLinus Walleij 	 * 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
174de8860b1SLinus Walleij 	 *    x  x  x  x  x  x  x  x  x  x  x  x  x
175de8860b1SLinus Walleij 	 */
176de8860b1SLinus Walleij 	val = get_unaligned_be16(&data[0]);
177de8860b1SLinus Walleij 	val = FIELD_GET(GENMASK(14, 2), val);
178de8860b1SLinus Walleij 	return val;
179de8860b1SLinus Walleij }
180de8860b1SLinus Walleij 
181de8860b1SLinus Walleij /**
182de8860b1SLinus Walleij  * yas5xx_measure() - Make a measure from the hardware
183de8860b1SLinus Walleij  * @yas5xx: The device state
184de8860b1SLinus Walleij  * @t: the raw temperature measurement
185de8860b1SLinus Walleij  * @x: the raw x axis measurement
186de8860b1SLinus Walleij  * @y1: the y1 axis measurement
187de8860b1SLinus Walleij  * @y2: the y2 axis measurement
188de8860b1SLinus Walleij  * @return: 0 on success or error code
189de8860b1SLinus Walleij  */
190de8860b1SLinus Walleij static int yas5xx_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)
191de8860b1SLinus Walleij {
192de8860b1SLinus Walleij 	unsigned int busy;
193de8860b1SLinus Walleij 	u8 data[8];
194de8860b1SLinus Walleij 	int ret;
195de8860b1SLinus Walleij 	u16 val;
196de8860b1SLinus Walleij 
197de8860b1SLinus Walleij 	mutex_lock(&yas5xx->lock);
198de8860b1SLinus Walleij 	ret = regmap_write(yas5xx->map, YAS5XX_MEASURE, YAS5XX_MEASURE_START);
199de8860b1SLinus Walleij 	if (ret < 0)
200de8860b1SLinus Walleij 		goto out_unlock;
201de8860b1SLinus Walleij 
202de8860b1SLinus Walleij 	/*
203de8860b1SLinus Walleij 	 * Typical time to measure 1500 us, max 2000 us so wait min 500 us
204de8860b1SLinus Walleij 	 * and at most 20000 us (one magnitude more than the datsheet max)
205de8860b1SLinus Walleij 	 * before timeout.
206de8860b1SLinus Walleij 	 */
207de8860b1SLinus Walleij 	ret = regmap_read_poll_timeout(yas5xx->map, YAS5XX_MEASURE_DATA, busy,
208de8860b1SLinus Walleij 				       !(busy & YAS5XX_MEASURE_DATA_BUSY),
209de8860b1SLinus Walleij 				       500, 20000);
210de8860b1SLinus Walleij 	if (ret) {
211de8860b1SLinus Walleij 		dev_err(yas5xx->dev, "timeout waiting for measurement\n");
212de8860b1SLinus Walleij 		goto out_unlock;
213de8860b1SLinus Walleij 	}
214de8860b1SLinus Walleij 
215de8860b1SLinus Walleij 	ret = regmap_bulk_read(yas5xx->map, YAS5XX_MEASURE_DATA,
216de8860b1SLinus Walleij 			       data, sizeof(data));
217de8860b1SLinus Walleij 	if (ret)
218de8860b1SLinus Walleij 		goto out_unlock;
219de8860b1SLinus Walleij 
220de8860b1SLinus Walleij 	mutex_unlock(&yas5xx->lock);
221de8860b1SLinus Walleij 
222de8860b1SLinus Walleij 	switch (yas5xx->devid) {
223de8860b1SLinus Walleij 	case YAS530_DEVICE_ID:
224de8860b1SLinus Walleij 		/*
225de8860b1SLinus Walleij 		 * The t value is 9 bits in big endian format
226de8860b1SLinus Walleij 		 * These are the bits used in a 16bit word:
227de8860b1SLinus Walleij 		 * 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
228de8860b1SLinus Walleij 		 *    x  x  x  x  x  x  x  x  x
229de8860b1SLinus Walleij 		 */
230de8860b1SLinus Walleij 		val = get_unaligned_be16(&data[0]);
231de8860b1SLinus Walleij 		val = FIELD_GET(GENMASK(14, 6), val);
232de8860b1SLinus Walleij 		*t = val;
233de8860b1SLinus Walleij 		*x = yas530_extract_axis(&data[2]);
234de8860b1SLinus Walleij 		*y1 = yas530_extract_axis(&data[4]);
235de8860b1SLinus Walleij 		*y2 = yas530_extract_axis(&data[6]);
236de8860b1SLinus Walleij 		break;
237de8860b1SLinus Walleij 	case YAS532_DEVICE_ID:
238de8860b1SLinus Walleij 		/*
239de8860b1SLinus Walleij 		 * The t value is 10 bits in big endian format
240de8860b1SLinus Walleij 		 * These are the bits used in a 16bit word:
241de8860b1SLinus Walleij 		 * 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
242de8860b1SLinus Walleij 		 *    x  x  x  x  x  x  x  x  x  x
243de8860b1SLinus Walleij 		 */
244de8860b1SLinus Walleij 		val = get_unaligned_be16(&data[0]);
245de8860b1SLinus Walleij 		val = FIELD_GET(GENMASK(14, 5), val);
246de8860b1SLinus Walleij 		*t = val;
247de8860b1SLinus Walleij 		*x = yas532_extract_axis(&data[2]);
248de8860b1SLinus Walleij 		*y1 = yas532_extract_axis(&data[4]);
249de8860b1SLinus Walleij 		*y2 = yas532_extract_axis(&data[6]);
250de8860b1SLinus Walleij 		break;
251de8860b1SLinus Walleij 	default:
252de8860b1SLinus Walleij 		dev_err(yas5xx->dev, "unknown data format\n");
253de8860b1SLinus Walleij 		ret = -EINVAL;
254de8860b1SLinus Walleij 		break;
255de8860b1SLinus Walleij 	}
256de8860b1SLinus Walleij 
257de8860b1SLinus Walleij 	return ret;
258de8860b1SLinus Walleij 
259de8860b1SLinus Walleij out_unlock:
260de8860b1SLinus Walleij 	mutex_unlock(&yas5xx->lock);
261de8860b1SLinus Walleij 	return ret;
262de8860b1SLinus Walleij }
263de8860b1SLinus Walleij 
264de8860b1SLinus Walleij static s32 yas5xx_linearize(struct yas5xx *yas5xx, u16 val, int axis)
265de8860b1SLinus Walleij {
266de8860b1SLinus Walleij 	struct yas5xx_calibration *c = &yas5xx->calibration;
267de8860b1SLinus Walleij 	static const s32 yas532ac_coef[] = {
268de8860b1SLinus Walleij 		YAS532_VERSION_AC_COEF_X,
269de8860b1SLinus Walleij 		YAS532_VERSION_AC_COEF_Y1,
270de8860b1SLinus Walleij 		YAS532_VERSION_AC_COEF_Y2,
271de8860b1SLinus Walleij 	};
272de8860b1SLinus Walleij 	s32 coef;
273de8860b1SLinus Walleij 
274de8860b1SLinus Walleij 	/* Select coefficients */
275de8860b1SLinus Walleij 	switch (yas5xx->devid) {
276de8860b1SLinus Walleij 	case YAS530_DEVICE_ID:
277de8860b1SLinus Walleij 		if (yas5xx->version == YAS530_VERSION_A)
278de8860b1SLinus Walleij 			coef = YAS530_VERSION_A_COEF;
279de8860b1SLinus Walleij 		else
280de8860b1SLinus Walleij 			coef = YAS530_VERSION_B_COEF;
281de8860b1SLinus Walleij 		break;
282de8860b1SLinus Walleij 	case YAS532_DEVICE_ID:
283de8860b1SLinus Walleij 		if (yas5xx->version == YAS532_VERSION_AB)
284de8860b1SLinus Walleij 			coef = YAS532_VERSION_AB_COEF;
285de8860b1SLinus Walleij 		else
286de8860b1SLinus Walleij 			/* Elaborate coefficients */
287de8860b1SLinus Walleij 			coef = yas532ac_coef[axis];
288de8860b1SLinus Walleij 		break;
289de8860b1SLinus Walleij 	default:
290de8860b1SLinus Walleij 		dev_err(yas5xx->dev, "unknown device type\n");
291de8860b1SLinus Walleij 		return val;
292de8860b1SLinus Walleij 	}
293de8860b1SLinus Walleij 	/*
294de8860b1SLinus Walleij 	 * Linearization formula:
295de8860b1SLinus Walleij 	 *
296de8860b1SLinus Walleij 	 * x' = x - (3721 + 50 * f) + (xoffset - r) * c
297de8860b1SLinus Walleij 	 *
298de8860b1SLinus Walleij 	 * Where f and r are calibration values, c is a per-device
299de8860b1SLinus Walleij 	 * and sometimes per-axis coefficient.
300de8860b1SLinus Walleij 	 */
301de8860b1SLinus Walleij 	return val - (3721 + 50 * c->f[axis]) +
302de8860b1SLinus Walleij 		(yas5xx->hard_offsets[axis] - c->r[axis]) * coef;
303de8860b1SLinus Walleij }
304de8860b1SLinus Walleij 
305de8860b1SLinus Walleij /**
306de8860b1SLinus Walleij  * yas5xx_get_measure() - Measure a sample of all axis and process
307de8860b1SLinus Walleij  * @yas5xx: The device state
308de8860b1SLinus Walleij  * @to: Temperature out
309de8860b1SLinus Walleij  * @xo: X axis out
310de8860b1SLinus Walleij  * @yo: Y axis out
311de8860b1SLinus Walleij  * @zo: Z axis out
312de8860b1SLinus Walleij  * @return: 0 on success or error code
313de8860b1SLinus Walleij  *
314de8860b1SLinus Walleij  * Returned values are in nanotesla according to some code.
315de8860b1SLinus Walleij  */
316de8860b1SLinus Walleij static int yas5xx_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
317de8860b1SLinus Walleij {
318de8860b1SLinus Walleij 	struct yas5xx_calibration *c = &yas5xx->calibration;
319de8860b1SLinus Walleij 	u16 t, x, y1, y2;
320de8860b1SLinus Walleij 	/* These are "signed x, signed y1 etc */
321de8860b1SLinus Walleij 	s32 sx, sy1, sy2, sy, sz;
322de8860b1SLinus Walleij 	int ret;
323de8860b1SLinus Walleij 
324de8860b1SLinus Walleij 	/* We first get raw data that needs to be translated to [x,y,z] */
325de8860b1SLinus Walleij 	ret = yas5xx_measure(yas5xx, &t, &x, &y1, &y2);
326de8860b1SLinus Walleij 	if (ret)
327de8860b1SLinus Walleij 		return ret;
328de8860b1SLinus Walleij 
329de8860b1SLinus Walleij 	/* Do some linearization if available */
330de8860b1SLinus Walleij 	sx = yas5xx_linearize(yas5xx, x, 0);
331de8860b1SLinus Walleij 	sy1 = yas5xx_linearize(yas5xx, y1, 1);
332de8860b1SLinus Walleij 	sy2 = yas5xx_linearize(yas5xx, y2, 2);
333de8860b1SLinus Walleij 
334de8860b1SLinus Walleij 	/*
335de8860b1SLinus Walleij 	 * Temperature compensation for x, y1, y2 respectively:
336de8860b1SLinus Walleij 	 *
337de8860b1SLinus Walleij 	 *          Cx * t
338de8860b1SLinus Walleij 	 * x' = x - ------
339de8860b1SLinus Walleij 	 *           100
340de8860b1SLinus Walleij 	 */
341de8860b1SLinus Walleij 	sx = sx - (c->Cx * t) / 100;
342de8860b1SLinus Walleij 	sy1 = sy1 - (c->Cy1 * t) / 100;
343de8860b1SLinus Walleij 	sy2 = sy2 - (c->Cy2 * t) / 100;
344de8860b1SLinus Walleij 
345de8860b1SLinus Walleij 	/*
346de8860b1SLinus Walleij 	 * Break y1 and y2 into y and z, y1 and y2 are apparently encoding
347de8860b1SLinus Walleij 	 * y and z.
348de8860b1SLinus Walleij 	 */
349de8860b1SLinus Walleij 	sy = sy1 - sy2;
350de8860b1SLinus Walleij 	sz = -sy1 - sy2;
351de8860b1SLinus Walleij 
352de8860b1SLinus Walleij 	/*
353de8860b1SLinus Walleij 	 * FIXME: convert to Celsius? Just guessing this is given
354de8860b1SLinus Walleij 	 * as 1/10:s of degrees so multiply by 100 to get millicentigrades.
355de8860b1SLinus Walleij 	 */
356de8860b1SLinus Walleij 	*to = t * 100;
357de8860b1SLinus Walleij 	/*
358de8860b1SLinus Walleij 	 * Calibrate [x,y,z] with some formulas like this:
359de8860b1SLinus Walleij 	 *
360de8860b1SLinus Walleij 	 *            100 * x + a_2 * y + a_3 * z
361de8860b1SLinus Walleij 	 *  x' = k *  ---------------------------
362de8860b1SLinus Walleij 	 *                        10
363de8860b1SLinus Walleij 	 *
364de8860b1SLinus Walleij 	 *           a_4 * x + a_5 * y + a_6 * z
365de8860b1SLinus Walleij 	 *  y' = k * ---------------------------
366de8860b1SLinus Walleij 	 *                        10
367de8860b1SLinus Walleij 	 *
368de8860b1SLinus Walleij 	 *           a_7 * x + a_8 * y + a_9 * z
369de8860b1SLinus Walleij 	 *  z' = k * ---------------------------
370de8860b1SLinus Walleij 	 *                        10
371de8860b1SLinus Walleij 	 */
372de8860b1SLinus Walleij 	*xo = c->k * ((100 * sx + c->a2 * sy + c->a3 * sz) / 10);
373de8860b1SLinus Walleij 	*yo = c->k * ((c->a4 * sx + c->a5 * sy + c->a6 * sz) / 10);
374de8860b1SLinus Walleij 	*zo = c->k * ((c->a7 * sx + c->a8 * sy + c->a9 * sz) / 10);
375de8860b1SLinus Walleij 
376de8860b1SLinus Walleij 	return 0;
377de8860b1SLinus Walleij }
378de8860b1SLinus Walleij 
379de8860b1SLinus Walleij static int yas5xx_read_raw(struct iio_dev *indio_dev,
380de8860b1SLinus Walleij 			   struct iio_chan_spec const *chan,
381de8860b1SLinus Walleij 			   int *val, int *val2,
382de8860b1SLinus Walleij 			   long mask)
383de8860b1SLinus Walleij {
384de8860b1SLinus Walleij 	struct yas5xx *yas5xx = iio_priv(indio_dev);
385de8860b1SLinus Walleij 	s32 t, x, y, z;
386de8860b1SLinus Walleij 	int ret;
387de8860b1SLinus Walleij 
388de8860b1SLinus Walleij 	switch (mask) {
389de8860b1SLinus Walleij 	case IIO_CHAN_INFO_RAW:
390de8860b1SLinus Walleij 		pm_runtime_get_sync(yas5xx->dev);
391de8860b1SLinus Walleij 		ret = yas5xx_get_measure(yas5xx, &t, &x, &y, &z);
392de8860b1SLinus Walleij 		pm_runtime_mark_last_busy(yas5xx->dev);
393de8860b1SLinus Walleij 		pm_runtime_put_autosuspend(yas5xx->dev);
394de8860b1SLinus Walleij 		if (ret)
395de8860b1SLinus Walleij 			return ret;
396de8860b1SLinus Walleij 		switch (chan->address) {
397de8860b1SLinus Walleij 		case 0:
398de8860b1SLinus Walleij 			*val = t;
399de8860b1SLinus Walleij 			break;
400de8860b1SLinus Walleij 		case 1:
401de8860b1SLinus Walleij 			*val = x;
402de8860b1SLinus Walleij 			break;
403de8860b1SLinus Walleij 		case 2:
404de8860b1SLinus Walleij 			*val = y;
405de8860b1SLinus Walleij 			break;
406de8860b1SLinus Walleij 		case 3:
407de8860b1SLinus Walleij 			*val = z;
408de8860b1SLinus Walleij 			break;
409de8860b1SLinus Walleij 		default:
410de8860b1SLinus Walleij 			dev_err(yas5xx->dev, "unknown channel\n");
411de8860b1SLinus Walleij 			return -EINVAL;
412de8860b1SLinus Walleij 		}
413de8860b1SLinus Walleij 		return IIO_VAL_INT;
414de8860b1SLinus Walleij 	case IIO_CHAN_INFO_SCALE:
415de8860b1SLinus Walleij 		if (chan->address == 0) {
416de8860b1SLinus Walleij 			/* Temperature is unscaled */
417de8860b1SLinus Walleij 			*val = 1;
418de8860b1SLinus Walleij 			return IIO_VAL_INT;
419de8860b1SLinus Walleij 		}
420de8860b1SLinus Walleij 		/*
421de8860b1SLinus Walleij 		 * The axis values are in nanotesla according to the vendor
422de8860b1SLinus Walleij 		 * drivers, but is clearly in microtesla according to
423de8860b1SLinus Walleij 		 * experiments. Since 1 uT = 0.01 Gauss, we need to divide
424de8860b1SLinus Walleij 		 * by 100000000 (10^8) to get to Gauss from the raw value.
425de8860b1SLinus Walleij 		 */
426de8860b1SLinus Walleij 		*val = 1;
427de8860b1SLinus Walleij 		*val2 = 100000000;
428de8860b1SLinus Walleij 		return IIO_VAL_FRACTIONAL;
429de8860b1SLinus Walleij 	default:
430de8860b1SLinus Walleij 		/* Unknown request */
431de8860b1SLinus Walleij 		return -EINVAL;
432de8860b1SLinus Walleij 	}
433de8860b1SLinus Walleij }
434de8860b1SLinus Walleij 
435de8860b1SLinus Walleij static void yas5xx_fill_buffer(struct iio_dev *indio_dev)
436de8860b1SLinus Walleij {
437de8860b1SLinus Walleij 	struct yas5xx *yas5xx = iio_priv(indio_dev);
438de8860b1SLinus Walleij 	s32 t, x, y, z;
439de8860b1SLinus Walleij 	int ret;
440de8860b1SLinus Walleij 
441de8860b1SLinus Walleij 	pm_runtime_get_sync(yas5xx->dev);
442de8860b1SLinus Walleij 	ret = yas5xx_get_measure(yas5xx, &t, &x, &y, &z);
443de8860b1SLinus Walleij 	pm_runtime_mark_last_busy(yas5xx->dev);
444de8860b1SLinus Walleij 	pm_runtime_put_autosuspend(yas5xx->dev);
445de8860b1SLinus Walleij 	if (ret) {
446de8860b1SLinus Walleij 		dev_err(yas5xx->dev, "error refilling buffer\n");
447de8860b1SLinus Walleij 		return;
448de8860b1SLinus Walleij 	}
449de8860b1SLinus Walleij 	yas5xx->scan.channels[0] = t;
450de8860b1SLinus Walleij 	yas5xx->scan.channels[1] = x;
451de8860b1SLinus Walleij 	yas5xx->scan.channels[2] = y;
452de8860b1SLinus Walleij 	yas5xx->scan.channels[3] = z;
453de8860b1SLinus Walleij 	iio_push_to_buffers_with_timestamp(indio_dev, &yas5xx->scan,
454de8860b1SLinus Walleij 					   iio_get_time_ns(indio_dev));
455de8860b1SLinus Walleij }
456de8860b1SLinus Walleij 
457de8860b1SLinus Walleij static irqreturn_t yas5xx_handle_trigger(int irq, void *p)
458de8860b1SLinus Walleij {
459de8860b1SLinus Walleij 	const struct iio_poll_func *pf = p;
460de8860b1SLinus Walleij 	struct iio_dev *indio_dev = pf->indio_dev;
461de8860b1SLinus Walleij 
462de8860b1SLinus Walleij 	yas5xx_fill_buffer(indio_dev);
463de8860b1SLinus Walleij 	iio_trigger_notify_done(indio_dev->trig);
464de8860b1SLinus Walleij 
465de8860b1SLinus Walleij 	return IRQ_HANDLED;
466de8860b1SLinus Walleij }
467de8860b1SLinus Walleij 
468de8860b1SLinus Walleij 
469de8860b1SLinus Walleij static const struct iio_mount_matrix *
470de8860b1SLinus Walleij yas5xx_get_mount_matrix(const struct iio_dev *indio_dev,
471de8860b1SLinus Walleij 			const struct iio_chan_spec *chan)
472de8860b1SLinus Walleij {
473de8860b1SLinus Walleij 	struct yas5xx *yas5xx = iio_priv(indio_dev);
474de8860b1SLinus Walleij 
475de8860b1SLinus Walleij 	return &yas5xx->orientation;
476de8860b1SLinus Walleij }
477de8860b1SLinus Walleij 
478de8860b1SLinus Walleij static const struct iio_chan_spec_ext_info yas5xx_ext_info[] = {
479de8860b1SLinus Walleij 	IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, yas5xx_get_mount_matrix),
480de8860b1SLinus Walleij 	{ }
481de8860b1SLinus Walleij };
482de8860b1SLinus Walleij 
483de8860b1SLinus Walleij #define YAS5XX_AXIS_CHANNEL(axis, index)				\
484de8860b1SLinus Walleij 	{								\
485de8860b1SLinus Walleij 		.type = IIO_MAGN,					\
486de8860b1SLinus Walleij 		.modified = 1,						\
487de8860b1SLinus Walleij 		.channel2 = IIO_MOD_##axis,				\
488de8860b1SLinus Walleij 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
489de8860b1SLinus Walleij 			BIT(IIO_CHAN_INFO_SCALE),			\
490de8860b1SLinus Walleij 		.ext_info = yas5xx_ext_info,				\
491de8860b1SLinus Walleij 		.address = index,					\
492de8860b1SLinus Walleij 		.scan_index = index,					\
493de8860b1SLinus Walleij 		.scan_type = {						\
494de8860b1SLinus Walleij 			.sign = 's',					\
495de8860b1SLinus Walleij 			.realbits = 32,					\
496de8860b1SLinus Walleij 			.storagebits = 32,				\
497de8860b1SLinus Walleij 			.endianness = IIO_CPU,				\
498de8860b1SLinus Walleij 		},							\
499de8860b1SLinus Walleij 	}
500de8860b1SLinus Walleij 
501de8860b1SLinus Walleij static const struct iio_chan_spec yas5xx_channels[] = {
502de8860b1SLinus Walleij 	{
503de8860b1SLinus Walleij 		.type = IIO_TEMP,
504de8860b1SLinus Walleij 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
505de8860b1SLinus Walleij 		.address = 0,
506de8860b1SLinus Walleij 		.scan_index = 0,
507de8860b1SLinus Walleij 		.scan_type = {
508de8860b1SLinus Walleij 			.sign = 'u',
509de8860b1SLinus Walleij 			.realbits = 32,
510de8860b1SLinus Walleij 			.storagebits = 32,
511de8860b1SLinus Walleij 			.endianness = IIO_CPU,
512de8860b1SLinus Walleij 		},
513de8860b1SLinus Walleij 	},
514de8860b1SLinus Walleij 	YAS5XX_AXIS_CHANNEL(X, 1),
515de8860b1SLinus Walleij 	YAS5XX_AXIS_CHANNEL(Y, 2),
516de8860b1SLinus Walleij 	YAS5XX_AXIS_CHANNEL(Z, 3),
517de8860b1SLinus Walleij 	IIO_CHAN_SOFT_TIMESTAMP(4),
518de8860b1SLinus Walleij };
519de8860b1SLinus Walleij 
520de8860b1SLinus Walleij static const unsigned long yas5xx_scan_masks[] = { GENMASK(3, 0), 0 };
521de8860b1SLinus Walleij 
522de8860b1SLinus Walleij static const struct iio_info yas5xx_info = {
523de8860b1SLinus Walleij 	.read_raw = &yas5xx_read_raw,
524de8860b1SLinus Walleij };
525de8860b1SLinus Walleij 
526de8860b1SLinus Walleij static bool yas5xx_volatile_reg(struct device *dev, unsigned int reg)
527de8860b1SLinus Walleij {
528de8860b1SLinus Walleij 	return reg == YAS5XX_ACTUATE_INIT_COIL ||
529de8860b1SLinus Walleij 		reg == YAS5XX_MEASURE ||
530de8860b1SLinus Walleij 		(reg >= YAS5XX_MEASURE_DATA && reg <= YAS5XX_MEASURE_DATA + 8);
531de8860b1SLinus Walleij }
532de8860b1SLinus Walleij 
533de8860b1SLinus Walleij /* TODO: enable regmap cache, using mark dirty and sync at runtime resume */
534de8860b1SLinus Walleij static const struct regmap_config yas5xx_regmap_config = {
535de8860b1SLinus Walleij 	.reg_bits = 8,
536de8860b1SLinus Walleij 	.val_bits = 8,
537de8860b1SLinus Walleij 	.max_register = 0xff,
538de8860b1SLinus Walleij 	.volatile_reg = yas5xx_volatile_reg,
539de8860b1SLinus Walleij };
540de8860b1SLinus Walleij 
541de8860b1SLinus Walleij /**
542de8860b1SLinus Walleij  * yas53x_extract_calibration() - extracts the a2-a9 and k calibration
543de8860b1SLinus Walleij  * @data: the bitfield to use
544de8860b1SLinus Walleij  * @c: the calibration to populate
545de8860b1SLinus Walleij  */
546de8860b1SLinus Walleij static void yas53x_extract_calibration(u8 *data, struct yas5xx_calibration *c)
547de8860b1SLinus Walleij {
548de8860b1SLinus Walleij 	u64 val = get_unaligned_be64(data);
549de8860b1SLinus Walleij 
550de8860b1SLinus Walleij 	/*
551de8860b1SLinus Walleij 	 * Bitfield layout for the axis calibration data, for factor
552de8860b1SLinus Walleij 	 * a2 = 2 etc, k = k, c = clock divider
553de8860b1SLinus Walleij 	 *
554de8860b1SLinus Walleij 	 * n   7 6 5 4 3 2 1 0
555de8860b1SLinus Walleij 	 * 0 [ 2 2 2 2 2 2 3 3 ] bits 63 .. 56
556de8860b1SLinus Walleij 	 * 1 [ 3 3 4 4 4 4 4 4 ] bits 55 .. 48
557de8860b1SLinus Walleij 	 * 2 [ 5 5 5 5 5 5 6 6 ] bits 47 .. 40
558de8860b1SLinus Walleij 	 * 3 [ 6 6 6 6 7 7 7 7 ] bits 39 .. 32
559de8860b1SLinus Walleij 	 * 4 [ 7 7 7 8 8 8 8 8 ] bits 31 .. 24
560de8860b1SLinus Walleij 	 * 5 [ 8 9 9 9 9 9 9 9 ] bits 23 .. 16
561de8860b1SLinus Walleij 	 * 6 [ 9 k k k k k c c ] bits 15 .. 8
562de8860b1SLinus Walleij 	 * 7 [ c x x x x x x x ] bits  7 .. 0
563de8860b1SLinus Walleij 	 */
564de8860b1SLinus Walleij 	c->a2 = FIELD_GET(GENMASK_ULL(63, 58), val) - 32;
565de8860b1SLinus Walleij 	c->a3 = FIELD_GET(GENMASK_ULL(57, 54), val) - 8;
566de8860b1SLinus Walleij 	c->a4 = FIELD_GET(GENMASK_ULL(53, 48), val) - 32;
567de8860b1SLinus Walleij 	c->a5 = FIELD_GET(GENMASK_ULL(47, 42), val) + 38;
568de8860b1SLinus Walleij 	c->a6 = FIELD_GET(GENMASK_ULL(41, 36), val) - 32;
569de8860b1SLinus Walleij 	c->a7 = FIELD_GET(GENMASK_ULL(35, 29), val) - 64;
570de8860b1SLinus Walleij 	c->a8 = FIELD_GET(GENMASK_ULL(28, 23), val) - 32;
571de8860b1SLinus Walleij 	c->a9 = FIELD_GET(GENMASK_ULL(22, 15), val);
572de8860b1SLinus Walleij 	c->k = FIELD_GET(GENMASK_ULL(14, 10), val) + 10;
573de8860b1SLinus Walleij 	c->dck = FIELD_GET(GENMASK_ULL(9, 7), val);
574de8860b1SLinus Walleij }
575de8860b1SLinus Walleij 
576de8860b1SLinus Walleij static int yas530_get_calibration_data(struct yas5xx *yas5xx)
577de8860b1SLinus Walleij {
578de8860b1SLinus Walleij 	struct yas5xx_calibration *c = &yas5xx->calibration;
579de8860b1SLinus Walleij 	u8 data[16];
580de8860b1SLinus Walleij 	u32 val;
581de8860b1SLinus Walleij 	int ret;
582de8860b1SLinus Walleij 
583de8860b1SLinus Walleij 	/* Dummy read, first read is ALWAYS wrong */
584de8860b1SLinus Walleij 	ret = regmap_bulk_read(yas5xx->map, YAS5XX_CAL, data, sizeof(data));
585de8860b1SLinus Walleij 	if (ret)
586de8860b1SLinus Walleij 		return ret;
587de8860b1SLinus Walleij 
588de8860b1SLinus Walleij 	/* Actual calibration readout */
589de8860b1SLinus Walleij 	ret = regmap_bulk_read(yas5xx->map, YAS5XX_CAL, data, sizeof(data));
590de8860b1SLinus Walleij 	if (ret)
591de8860b1SLinus Walleij 		return ret;
592de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "calibration data: %*ph\n", 14, data);
593de8860b1SLinus Walleij 
594de8860b1SLinus Walleij 	add_device_randomness(data, sizeof(data));
595de8860b1SLinus Walleij 	yas5xx->version = data[15] & GENMASK(1, 0);
596de8860b1SLinus Walleij 
597de8860b1SLinus Walleij 	/* Extract the calibration from the bitfield */
598de8860b1SLinus Walleij 	c->Cx = data[0] * 6 - 768;
599de8860b1SLinus Walleij 	c->Cy1 = data[1] * 6 - 768;
600de8860b1SLinus Walleij 	c->Cy2 = data[2] * 6 - 768;
601de8860b1SLinus Walleij 	yas53x_extract_calibration(&data[3], c);
602de8860b1SLinus Walleij 
603de8860b1SLinus Walleij 	/*
604de8860b1SLinus Walleij 	 * Extract linearization:
605de8860b1SLinus Walleij 	 * Linearization layout in the 32 bits at byte 11:
606de8860b1SLinus Walleij 	 * The r factors are 6 bit values where bit 5 is the sign
607de8860b1SLinus Walleij 	 *
608de8860b1SLinus Walleij 	 * n    7  6  5  4  3  2  1  0
609de8860b1SLinus Walleij 	 * 0 [ xx xx xx r0 r0 r0 r0 r0 ] bits 31 .. 24
610de8860b1SLinus Walleij 	 * 1 [ r0 f0 f0 r1 r1 r1 r1 r1 ] bits 23 .. 16
611de8860b1SLinus Walleij 	 * 2 [ r1 f1 f1 r2 r2 r2 r2 r2 ] bits 15 .. 8
612de8860b1SLinus Walleij 	 * 3 [ r2 f2 f2 xx xx xx xx xx ] bits  7 .. 0
613de8860b1SLinus Walleij 	 */
614de8860b1SLinus Walleij 	val = get_unaligned_be32(&data[11]);
615de8860b1SLinus Walleij 	c->f[0] = FIELD_GET(GENMASK(22, 21), val);
616de8860b1SLinus Walleij 	c->f[1] = FIELD_GET(GENMASK(14, 13), val);
617de8860b1SLinus Walleij 	c->f[2] = FIELD_GET(GENMASK(6, 5), val);
618de8860b1SLinus Walleij 	c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5);
619de8860b1SLinus Walleij 	c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5);
620de8860b1SLinus Walleij 	c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5);
621de8860b1SLinus Walleij 	return 0;
622de8860b1SLinus Walleij }
623de8860b1SLinus Walleij 
624de8860b1SLinus Walleij static int yas532_get_calibration_data(struct yas5xx *yas5xx)
625de8860b1SLinus Walleij {
626de8860b1SLinus Walleij 	struct yas5xx_calibration *c = &yas5xx->calibration;
627de8860b1SLinus Walleij 	u8 data[14];
628de8860b1SLinus Walleij 	u32 val;
629de8860b1SLinus Walleij 	int ret;
630de8860b1SLinus Walleij 
631de8860b1SLinus Walleij 	/* Dummy read, first read is ALWAYS wrong */
632de8860b1SLinus Walleij 	ret = regmap_bulk_read(yas5xx->map, YAS5XX_CAL, data, sizeof(data));
633de8860b1SLinus Walleij 	if (ret)
634de8860b1SLinus Walleij 		return ret;
635de8860b1SLinus Walleij 	/* Actual calibration readout */
636de8860b1SLinus Walleij 	ret = regmap_bulk_read(yas5xx->map, YAS5XX_CAL, data, sizeof(data));
637de8860b1SLinus Walleij 	if (ret)
638de8860b1SLinus Walleij 		return ret;
639de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "calibration data: %*ph\n", 14, data);
640de8860b1SLinus Walleij 
641de8860b1SLinus Walleij 	/* Sanity check, is this all zeroes? */
642de8860b1SLinus Walleij 	if (memchr_inv(data, 0x00, 13)) {
643de8860b1SLinus Walleij 		if (!(data[13] & BIT(7)))
644de8860b1SLinus Walleij 			dev_warn(yas5xx->dev, "calibration is blank!\n");
645de8860b1SLinus Walleij 	}
646de8860b1SLinus Walleij 
647de8860b1SLinus Walleij 	add_device_randomness(data, sizeof(data));
648de8860b1SLinus Walleij 	/* Only one bit of version info reserved here as far as we know */
649de8860b1SLinus Walleij 	yas5xx->version = data[13] & BIT(0);
650de8860b1SLinus Walleij 
651de8860b1SLinus Walleij 	/* Extract calibration from the bitfield */
652de8860b1SLinus Walleij 	c->Cx = data[0] * 10 - 1280;
653de8860b1SLinus Walleij 	c->Cy1 = data[1] * 10 - 1280;
654de8860b1SLinus Walleij 	c->Cy2 = data[2] * 10 - 1280;
655de8860b1SLinus Walleij 	yas53x_extract_calibration(&data[3], c);
656de8860b1SLinus Walleij 	/*
657de8860b1SLinus Walleij 	 * Extract linearization:
658de8860b1SLinus Walleij 	 * Linearization layout in the 32 bits at byte 10:
659de8860b1SLinus Walleij 	 * The r factors are 6 bit values where bit 5 is the sign
660de8860b1SLinus Walleij 	 *
661de8860b1SLinus Walleij 	 * n    7  6  5  4  3  2  1  0
662de8860b1SLinus Walleij 	 * 0 [ xx r0 r0 r0 r0 r0 r0 f0 ] bits 31 .. 24
663de8860b1SLinus Walleij 	 * 1 [ f0 r1 r1 r1 r1 r1 r1 f1 ] bits 23 .. 16
664de8860b1SLinus Walleij 	 * 2 [ f1 r2 r2 r2 r2 r2 r2 f2 ] bits 15 .. 8
665de8860b1SLinus Walleij 	 * 3 [ f2 xx xx xx xx xx xx xx ] bits  7 .. 0
666de8860b1SLinus Walleij 	 */
667de8860b1SLinus Walleij 	val = get_unaligned_be32(&data[10]);
668de8860b1SLinus Walleij 	c->f[0] = FIELD_GET(GENMASK(24, 23), val);
669de8860b1SLinus Walleij 	c->f[1] = FIELD_GET(GENMASK(16, 15), val);
670de8860b1SLinus Walleij 	c->f[2] = FIELD_GET(GENMASK(8, 7), val);
671de8860b1SLinus Walleij 	c->r[0] = sign_extend32(FIELD_GET(GENMASK(30, 25), val), 5);
672de8860b1SLinus Walleij 	c->r[1] = sign_extend32(FIELD_GET(GENMASK(22, 17), val), 5);
673de8860b1SLinus Walleij 	c->r[2] = sign_extend32(FIELD_GET(GENMASK(14, 7), val), 5);
674de8860b1SLinus Walleij 
675de8860b1SLinus Walleij 	return 0;
676de8860b1SLinus Walleij }
677de8860b1SLinus Walleij 
678de8860b1SLinus Walleij static void yas5xx_dump_calibration(struct yas5xx *yas5xx)
679de8860b1SLinus Walleij {
680de8860b1SLinus Walleij 	struct yas5xx_calibration *c = &yas5xx->calibration;
681de8860b1SLinus Walleij 
682de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "f[] = [%d, %d, %d]\n",
683de8860b1SLinus Walleij 		c->f[0], c->f[1], c->f[2]);
684de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "r[] = [%d, %d, %d]\n",
685de8860b1SLinus Walleij 		c->r[0], c->r[1], c->r[2]);
686de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "Cx = %d\n", c->Cx);
687de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "Cy1 = %d\n", c->Cy1);
688de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "Cy2 = %d\n", c->Cy2);
689de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "a2 = %d\n", c->a2);
690de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "a3 = %d\n", c->a3);
691de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "a4 = %d\n", c->a4);
692de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "a5 = %d\n", c->a5);
693de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "a6 = %d\n", c->a6);
694de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "a7 = %d\n", c->a7);
695de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "a8 = %d\n", c->a8);
696de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "a9 = %d\n", c->a9);
697de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "k = %d\n", c->k);
698de8860b1SLinus Walleij 	dev_dbg(yas5xx->dev, "dck = %d\n", c->dck);
699de8860b1SLinus Walleij }
700de8860b1SLinus Walleij 
701de8860b1SLinus Walleij static int yas5xx_set_offsets(struct yas5xx *yas5xx, s8 ox, s8 oy1, s8 oy2)
702de8860b1SLinus Walleij {
703de8860b1SLinus Walleij 	int ret;
704de8860b1SLinus Walleij 
705de8860b1SLinus Walleij 	ret = regmap_write(yas5xx->map, YAS5XX_OFFSET_X, ox);
706de8860b1SLinus Walleij 	if (ret)
707de8860b1SLinus Walleij 		return ret;
708de8860b1SLinus Walleij 	ret = regmap_write(yas5xx->map, YAS5XX_OFFSET_Y1, oy1);
709de8860b1SLinus Walleij 	if (ret)
710de8860b1SLinus Walleij 		return ret;
711de8860b1SLinus Walleij 	return regmap_write(yas5xx->map, YAS5XX_OFFSET_Y2, oy2);
712de8860b1SLinus Walleij }
713de8860b1SLinus Walleij 
714de8860b1SLinus Walleij static s8 yas5xx_adjust_offset(s8 old, int bit, u16 center, u16 measure)
715de8860b1SLinus Walleij {
716de8860b1SLinus Walleij 	if (measure > center)
717de8860b1SLinus Walleij 		return old + BIT(bit);
718de8860b1SLinus Walleij 	if (measure < center)
719de8860b1SLinus Walleij 		return old - BIT(bit);
720de8860b1SLinus Walleij 	return old;
721de8860b1SLinus Walleij }
722de8860b1SLinus Walleij 
723de8860b1SLinus Walleij static int yas5xx_meaure_offsets(struct yas5xx *yas5xx)
724de8860b1SLinus Walleij {
725de8860b1SLinus Walleij 	int ret;
726de8860b1SLinus Walleij 	u16 center;
727de8860b1SLinus Walleij 	u16 t, x, y1, y2;
728de8860b1SLinus Walleij 	s8 ox, oy1, oy2;
729de8860b1SLinus Walleij 	int i;
730de8860b1SLinus Walleij 
731de8860b1SLinus Walleij 	/* Actuate the init coil and measure offsets */
732de8860b1SLinus Walleij 	ret = regmap_write(yas5xx->map, YAS5XX_ACTUATE_INIT_COIL, 0);
733de8860b1SLinus Walleij 	if (ret)
734de8860b1SLinus Walleij 		return ret;
735de8860b1SLinus Walleij 
736de8860b1SLinus Walleij 	/* When the initcoil is active this should be around the center */
737de8860b1SLinus Walleij 	switch (yas5xx->devid) {
738de8860b1SLinus Walleij 	case YAS530_DEVICE_ID:
739de8860b1SLinus Walleij 		center = YAS530_DATA_CENTER;
740de8860b1SLinus Walleij 		break;
741de8860b1SLinus Walleij 	case YAS532_DEVICE_ID:
742de8860b1SLinus Walleij 		center = YAS532_DATA_CENTER;
743de8860b1SLinus Walleij 		break;
744de8860b1SLinus Walleij 	default:
745de8860b1SLinus Walleij 		dev_err(yas5xx->dev, "unknown device type\n");
746de8860b1SLinus Walleij 		return -EINVAL;
747de8860b1SLinus Walleij 	}
748de8860b1SLinus Walleij 
749de8860b1SLinus Walleij 	/*
750de8860b1SLinus Walleij 	 * We set offsets in the interval +-31 by iterating
751de8860b1SLinus Walleij 	 * +-16, +-8, +-4, +-2, +-1 adjusting the offsets each
752de8860b1SLinus Walleij 	 * time, then writing the final offsets into the
753de8860b1SLinus Walleij 	 * registers.
754de8860b1SLinus Walleij 	 *
755de8860b1SLinus Walleij 	 * NOTE: these offsets are NOT in the same unit or magnitude
756de8860b1SLinus Walleij 	 * as the values for [x, y1, y2]. The value is +/-31
757de8860b1SLinus Walleij 	 * but the effect on the raw values is much larger.
758de8860b1SLinus Walleij 	 * The effect of the offset is to bring the measure
759de8860b1SLinus Walleij 	 * rougly to the center.
760de8860b1SLinus Walleij 	 */
761de8860b1SLinus Walleij 	ox = 0;
762de8860b1SLinus Walleij 	oy1 = 0;
763de8860b1SLinus Walleij 	oy2 = 0;
764de8860b1SLinus Walleij 
765de8860b1SLinus Walleij 	for (i = 4; i >= 0; i--) {
766de8860b1SLinus Walleij 		ret = yas5xx_set_offsets(yas5xx, ox, oy1, oy2);
767de8860b1SLinus Walleij 		if (ret)
768de8860b1SLinus Walleij 			return ret;
769de8860b1SLinus Walleij 
770de8860b1SLinus Walleij 		ret = yas5xx_measure(yas5xx, &t, &x, &y1, &y2);
771de8860b1SLinus Walleij 		if (ret)
772de8860b1SLinus Walleij 			return ret;
773de8860b1SLinus Walleij 		dev_dbg(yas5xx->dev, "measurement %d: x=%d, y1=%d, y2=%d\n",
774de8860b1SLinus Walleij 			5-i, x, y1, y2);
775de8860b1SLinus Walleij 
776de8860b1SLinus Walleij 		ox = yas5xx_adjust_offset(ox, i, center, x);
777de8860b1SLinus Walleij 		oy1 = yas5xx_adjust_offset(oy1, i, center, y1);
778de8860b1SLinus Walleij 		oy2 = yas5xx_adjust_offset(oy2, i, center, y2);
779de8860b1SLinus Walleij 	}
780de8860b1SLinus Walleij 
781de8860b1SLinus Walleij 	/* Needed for calibration algorithm */
782de8860b1SLinus Walleij 	yas5xx->hard_offsets[0] = ox;
783de8860b1SLinus Walleij 	yas5xx->hard_offsets[1] = oy1;
784de8860b1SLinus Walleij 	yas5xx->hard_offsets[2] = oy2;
785de8860b1SLinus Walleij 	ret = yas5xx_set_offsets(yas5xx, ox, oy1, oy2);
786de8860b1SLinus Walleij 	if (ret)
787de8860b1SLinus Walleij 		return ret;
788de8860b1SLinus Walleij 
789de8860b1SLinus Walleij 	dev_info(yas5xx->dev, "discovered hard offsets: x=%d, y1=%d, y2=%d\n",
790de8860b1SLinus Walleij 		 ox, oy1, oy2);
791de8860b1SLinus Walleij 	return 0;
792de8860b1SLinus Walleij }
793de8860b1SLinus Walleij 
794de8860b1SLinus Walleij static int yas5xx_power_on(struct yas5xx *yas5xx)
795de8860b1SLinus Walleij {
796de8860b1SLinus Walleij 	unsigned int val;
797de8860b1SLinus Walleij 	int ret;
798de8860b1SLinus Walleij 
799de8860b1SLinus Walleij 	/* Zero the test registers */
800de8860b1SLinus Walleij 	ret = regmap_write(yas5xx->map, YAS5XX_TEST1, 0);
801de8860b1SLinus Walleij 	if (ret)
802de8860b1SLinus Walleij 		return ret;
803de8860b1SLinus Walleij 	ret = regmap_write(yas5xx->map, YAS5XX_TEST2, 0);
804de8860b1SLinus Walleij 	if (ret)
805de8860b1SLinus Walleij 		return ret;
806de8860b1SLinus Walleij 
807de8860b1SLinus Walleij 	/* Set up for no interrupts, calibrated clock divider */
808de8860b1SLinus Walleij 	val = FIELD_PREP(YAS5XX_CONFIG_CCK_MASK, yas5xx->calibration.dck);
809de8860b1SLinus Walleij 	ret = regmap_write(yas5xx->map, YAS5XX_CONFIG, val);
810de8860b1SLinus Walleij 	if (ret)
811de8860b1SLinus Walleij 		return ret;
812de8860b1SLinus Walleij 
813de8860b1SLinus Walleij 	/* Measure interval 0 (back-to-back?)  */
814de8860b1SLinus Walleij 	return regmap_write(yas5xx->map, YAS5XX_MEASURE_INTERVAL, 0);
815de8860b1SLinus Walleij }
816de8860b1SLinus Walleij 
817de8860b1SLinus Walleij static int yas5xx_probe(struct i2c_client *i2c,
818de8860b1SLinus Walleij 			const struct i2c_device_id *id)
819de8860b1SLinus Walleij {
820de8860b1SLinus Walleij 	struct iio_dev *indio_dev;
821de8860b1SLinus Walleij 	struct device *dev = &i2c->dev;
822de8860b1SLinus Walleij 	struct yas5xx *yas5xx;
823de8860b1SLinus Walleij 	int ret;
824de8860b1SLinus Walleij 
825de8860b1SLinus Walleij 	indio_dev = devm_iio_device_alloc(dev, sizeof(*yas5xx));
826de8860b1SLinus Walleij 	if (!indio_dev)
827de8860b1SLinus Walleij 		return -ENOMEM;
828de8860b1SLinus Walleij 
829de8860b1SLinus Walleij 	yas5xx = iio_priv(indio_dev);
830de8860b1SLinus Walleij 	i2c_set_clientdata(i2c, indio_dev);
831de8860b1SLinus Walleij 	yas5xx->dev = dev;
832de8860b1SLinus Walleij 	mutex_init(&yas5xx->lock);
833de8860b1SLinus Walleij 
834de8860b1SLinus Walleij 	ret = iio_read_mount_matrix(dev, "mount-matrix", &yas5xx->orientation);
835de8860b1SLinus Walleij 	if (ret)
836de8860b1SLinus Walleij 		return ret;
837de8860b1SLinus Walleij 
838de8860b1SLinus Walleij 	yas5xx->regs[0].supply = "vdd";
839de8860b1SLinus Walleij 	yas5xx->regs[1].supply = "iovdd";
840de8860b1SLinus Walleij 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(yas5xx->regs),
841de8860b1SLinus Walleij 				      yas5xx->regs);
842de8860b1SLinus Walleij 	if (ret)
843de8860b1SLinus Walleij 		return dev_err_probe(dev, ret, "cannot get regulators\n");
844de8860b1SLinus Walleij 
845de8860b1SLinus Walleij 	ret = regulator_bulk_enable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
846de8860b1SLinus Walleij 	if (ret) {
847de8860b1SLinus Walleij 		dev_err(dev, "cannot enable regulators\n");
848de8860b1SLinus Walleij 		return ret;
849de8860b1SLinus Walleij 	}
850de8860b1SLinus Walleij 
851de8860b1SLinus Walleij 	/* See comment in runtime resume callback */
852de8860b1SLinus Walleij 	usleep_range(31000, 40000);
853de8860b1SLinus Walleij 
854de8860b1SLinus Walleij 	/* This will take the device out of reset if need be */
855de8860b1SLinus Walleij 	yas5xx->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
856de8860b1SLinus Walleij 	if (IS_ERR(yas5xx->reset)) {
857de8860b1SLinus Walleij 		ret = dev_err_probe(dev, PTR_ERR(yas5xx->reset),
858de8860b1SLinus Walleij 				    "failed to get reset line\n");
859de8860b1SLinus Walleij 		goto reg_off;
860de8860b1SLinus Walleij 	}
861de8860b1SLinus Walleij 
862de8860b1SLinus Walleij 	yas5xx->map = devm_regmap_init_i2c(i2c, &yas5xx_regmap_config);
863de8860b1SLinus Walleij 	if (IS_ERR(yas5xx->map)) {
864de8860b1SLinus Walleij 		dev_err(dev, "failed to allocate register map\n");
865de8860b1SLinus Walleij 		ret = PTR_ERR(yas5xx->map);
866de8860b1SLinus Walleij 		goto assert_reset;
867de8860b1SLinus Walleij 	}
868de8860b1SLinus Walleij 
869de8860b1SLinus Walleij 	ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &yas5xx->devid);
870de8860b1SLinus Walleij 	if (ret)
871de8860b1SLinus Walleij 		goto assert_reset;
872de8860b1SLinus Walleij 
873de8860b1SLinus Walleij 	switch (yas5xx->devid) {
874de8860b1SLinus Walleij 	case YAS530_DEVICE_ID:
875de8860b1SLinus Walleij 		ret = yas530_get_calibration_data(yas5xx);
876de8860b1SLinus Walleij 		if (ret)
877de8860b1SLinus Walleij 			goto assert_reset;
878de8860b1SLinus Walleij 		dev_info(dev, "detected YAS530 MS-3E %s",
879de8860b1SLinus Walleij 			 yas5xx->version ? "B" : "A");
880de8860b1SLinus Walleij 		strncpy(yas5xx->name, "yas530", sizeof(yas5xx->name));
881de8860b1SLinus Walleij 		break;
882de8860b1SLinus Walleij 	case YAS532_DEVICE_ID:
883de8860b1SLinus Walleij 		ret = yas532_get_calibration_data(yas5xx);
884de8860b1SLinus Walleij 		if (ret)
885de8860b1SLinus Walleij 			goto assert_reset;
886de8860b1SLinus Walleij 		dev_info(dev, "detected YAS532/YAS533 MS-3R/F %s",
887de8860b1SLinus Walleij 			 yas5xx->version ? "AC" : "AB");
888de8860b1SLinus Walleij 		strncpy(yas5xx->name, "yas532", sizeof(yas5xx->name));
889de8860b1SLinus Walleij 		break;
890de8860b1SLinus Walleij 	default:
891e64837bfSLinus Walleij 		ret = -ENODEV;
892de8860b1SLinus Walleij 		dev_err(dev, "unhandled device ID %02x\n", yas5xx->devid);
893de8860b1SLinus Walleij 		goto assert_reset;
894de8860b1SLinus Walleij 	}
895de8860b1SLinus Walleij 
896de8860b1SLinus Walleij 	yas5xx_dump_calibration(yas5xx);
897de8860b1SLinus Walleij 	ret = yas5xx_power_on(yas5xx);
898de8860b1SLinus Walleij 	if (ret)
899de8860b1SLinus Walleij 		goto assert_reset;
900de8860b1SLinus Walleij 	ret = yas5xx_meaure_offsets(yas5xx);
901de8860b1SLinus Walleij 	if (ret)
902de8860b1SLinus Walleij 		goto assert_reset;
903de8860b1SLinus Walleij 
904de8860b1SLinus Walleij 	indio_dev->info = &yas5xx_info;
905de8860b1SLinus Walleij 	indio_dev->available_scan_masks = yas5xx_scan_masks;
906de8860b1SLinus Walleij 	indio_dev->modes = INDIO_DIRECT_MODE;
907de8860b1SLinus Walleij 	indio_dev->name = yas5xx->name;
908de8860b1SLinus Walleij 	indio_dev->channels = yas5xx_channels;
909de8860b1SLinus Walleij 	indio_dev->num_channels = ARRAY_SIZE(yas5xx_channels);
910de8860b1SLinus Walleij 
911de8860b1SLinus Walleij 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
912de8860b1SLinus Walleij 					 yas5xx_handle_trigger,
913de8860b1SLinus Walleij 					 NULL);
914de8860b1SLinus Walleij 	if (ret) {
915de8860b1SLinus Walleij 		dev_err(dev, "triggered buffer setup failed\n");
916de8860b1SLinus Walleij 		goto assert_reset;
917de8860b1SLinus Walleij 	}
918de8860b1SLinus Walleij 
919de8860b1SLinus Walleij 	ret = iio_device_register(indio_dev);
920de8860b1SLinus Walleij 	if (ret) {
921de8860b1SLinus Walleij 		dev_err(dev, "device register failed\n");
922de8860b1SLinus Walleij 		goto cleanup_buffer;
923de8860b1SLinus Walleij 	}
924de8860b1SLinus Walleij 
925de8860b1SLinus Walleij 	/* Take runtime PM online */
926de8860b1SLinus Walleij 	pm_runtime_get_noresume(dev);
927de8860b1SLinus Walleij 	pm_runtime_set_active(dev);
928de8860b1SLinus Walleij 	pm_runtime_enable(dev);
929de8860b1SLinus Walleij 
930de8860b1SLinus Walleij 	pm_runtime_set_autosuspend_delay(dev, YAS5XX_AUTOSUSPEND_DELAY_MS);
931de8860b1SLinus Walleij 	pm_runtime_use_autosuspend(dev);
932de8860b1SLinus Walleij 	pm_runtime_put(dev);
933de8860b1SLinus Walleij 
934de8860b1SLinus Walleij 	return 0;
935de8860b1SLinus Walleij 
936de8860b1SLinus Walleij cleanup_buffer:
937de8860b1SLinus Walleij 	iio_triggered_buffer_cleanup(indio_dev);
938de8860b1SLinus Walleij assert_reset:
939de8860b1SLinus Walleij 	gpiod_set_value_cansleep(yas5xx->reset, 1);
940de8860b1SLinus Walleij reg_off:
941de8860b1SLinus Walleij 	regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
942de8860b1SLinus Walleij 
943de8860b1SLinus Walleij 	return ret;
944de8860b1SLinus Walleij }
945de8860b1SLinus Walleij 
946de8860b1SLinus Walleij static int yas5xx_remove(struct i2c_client *i2c)
947de8860b1SLinus Walleij {
948de8860b1SLinus Walleij 	struct iio_dev *indio_dev = i2c_get_clientdata(i2c);
949de8860b1SLinus Walleij 	struct yas5xx *yas5xx = iio_priv(indio_dev);
950de8860b1SLinus Walleij 	struct device *dev = &i2c->dev;
951de8860b1SLinus Walleij 
952de8860b1SLinus Walleij 	iio_device_unregister(indio_dev);
953de8860b1SLinus Walleij 	iio_triggered_buffer_cleanup(indio_dev);
954de8860b1SLinus Walleij 	/*
955de8860b1SLinus Walleij 	 * Now we can't get any more reads from the device, which would
956de8860b1SLinus Walleij 	 * also call pm_runtime* functions and race with our disable
957de8860b1SLinus Walleij 	 * code. Disable PM runtime in orderly fashion and power down.
958de8860b1SLinus Walleij 	 */
959de8860b1SLinus Walleij 	pm_runtime_get_sync(dev);
960de8860b1SLinus Walleij 	pm_runtime_put_noidle(dev);
961de8860b1SLinus Walleij 	pm_runtime_disable(dev);
962de8860b1SLinus Walleij 	gpiod_set_value_cansleep(yas5xx->reset, 1);
963de8860b1SLinus Walleij 	regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
964de8860b1SLinus Walleij 
965de8860b1SLinus Walleij 	return 0;
966de8860b1SLinus Walleij }
967de8860b1SLinus Walleij 
968de8860b1SLinus Walleij static int __maybe_unused yas5xx_runtime_suspend(struct device *dev)
969de8860b1SLinus Walleij {
970de8860b1SLinus Walleij 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
971de8860b1SLinus Walleij 	struct yas5xx *yas5xx = iio_priv(indio_dev);
972de8860b1SLinus Walleij 
973de8860b1SLinus Walleij 	gpiod_set_value_cansleep(yas5xx->reset, 1);
974de8860b1SLinus Walleij 	regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
975de8860b1SLinus Walleij 
976de8860b1SLinus Walleij 	return 0;
977de8860b1SLinus Walleij }
978de8860b1SLinus Walleij 
979de8860b1SLinus Walleij static int __maybe_unused yas5xx_runtime_resume(struct device *dev)
980de8860b1SLinus Walleij {
981de8860b1SLinus Walleij 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
982de8860b1SLinus Walleij 	struct yas5xx *yas5xx = iio_priv(indio_dev);
983de8860b1SLinus Walleij 	int ret;
984de8860b1SLinus Walleij 
985de8860b1SLinus Walleij 	ret = regulator_bulk_enable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
986de8860b1SLinus Walleij 	if (ret) {
987de8860b1SLinus Walleij 		dev_err(dev, "cannot enable regulators\n");
988de8860b1SLinus Walleij 		return ret;
989de8860b1SLinus Walleij 	}
990de8860b1SLinus Walleij 
991de8860b1SLinus Walleij 	/*
992de8860b1SLinus Walleij 	 * The YAS530 datasheet says TVSKW is up to 30 ms, after that 1 ms
993de8860b1SLinus Walleij 	 * for all voltages to settle. The YAS532 is 10ms then 4ms for the
994de8860b1SLinus Walleij 	 * I2C to come online. Let's keep it safe and put this at 31ms.
995de8860b1SLinus Walleij 	 */
996de8860b1SLinus Walleij 	usleep_range(31000, 40000);
997de8860b1SLinus Walleij 	gpiod_set_value_cansleep(yas5xx->reset, 0);
998de8860b1SLinus Walleij 
999de8860b1SLinus Walleij 	ret = yas5xx_power_on(yas5xx);
1000de8860b1SLinus Walleij 	if (ret) {
1001de8860b1SLinus Walleij 		dev_err(dev, "cannot power on\n");
1002de8860b1SLinus Walleij 		goto out_reset;
1003de8860b1SLinus Walleij 	}
1004de8860b1SLinus Walleij 
1005de8860b1SLinus Walleij 	return 0;
1006de8860b1SLinus Walleij 
1007de8860b1SLinus Walleij out_reset:
1008de8860b1SLinus Walleij 	gpiod_set_value_cansleep(yas5xx->reset, 1);
1009de8860b1SLinus Walleij 	regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
1010de8860b1SLinus Walleij 
1011de8860b1SLinus Walleij 	return ret;
1012de8860b1SLinus Walleij }
1013de8860b1SLinus Walleij 
1014de8860b1SLinus Walleij static const struct dev_pm_ops yas5xx_dev_pm_ops = {
1015de8860b1SLinus Walleij 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1016de8860b1SLinus Walleij 				pm_runtime_force_resume)
1017de8860b1SLinus Walleij 	SET_RUNTIME_PM_OPS(yas5xx_runtime_suspend,
1018de8860b1SLinus Walleij 			   yas5xx_runtime_resume, NULL)
1019de8860b1SLinus Walleij };
1020de8860b1SLinus Walleij 
1021de8860b1SLinus Walleij static const struct i2c_device_id yas5xx_id[] = {
1022de8860b1SLinus Walleij 	{"yas530", },
1023de8860b1SLinus Walleij 	{"yas532", },
1024de8860b1SLinus Walleij 	{"yas533", },
1025de8860b1SLinus Walleij 	{}
1026de8860b1SLinus Walleij };
1027de8860b1SLinus Walleij MODULE_DEVICE_TABLE(i2c, yas5xx_id);
1028de8860b1SLinus Walleij 
1029de8860b1SLinus Walleij static const struct of_device_id yas5xx_of_match[] = {
1030de8860b1SLinus Walleij 	{ .compatible = "yamaha,yas530", },
1031de8860b1SLinus Walleij 	{ .compatible = "yamaha,yas532", },
1032de8860b1SLinus Walleij 	{ .compatible = "yamaha,yas533", },
1033de8860b1SLinus Walleij 	{}
1034de8860b1SLinus Walleij };
1035de8860b1SLinus Walleij MODULE_DEVICE_TABLE(of, yas5xx_of_match);
1036de8860b1SLinus Walleij 
1037de8860b1SLinus Walleij static struct i2c_driver yas5xx_driver = {
1038de8860b1SLinus Walleij 	.driver	 = {
1039de8860b1SLinus Walleij 		.name	= "yas5xx",
1040de8860b1SLinus Walleij 		.of_match_table = yas5xx_of_match,
1041de8860b1SLinus Walleij 		.pm = &yas5xx_dev_pm_ops,
1042de8860b1SLinus Walleij 	},
1043de8860b1SLinus Walleij 	.probe	  = yas5xx_probe,
1044de8860b1SLinus Walleij 	.remove	  = yas5xx_remove,
1045de8860b1SLinus Walleij 	.id_table = yas5xx_id,
1046de8860b1SLinus Walleij };
1047de8860b1SLinus Walleij module_i2c_driver(yas5xx_driver);
1048de8860b1SLinus Walleij 
1049de8860b1SLinus Walleij MODULE_DESCRIPTION("Yamaha YAS53x 3-axis magnetometer driver");
1050de8860b1SLinus Walleij MODULE_AUTHOR("Linus Walleij");
1051de8860b1SLinus Walleij MODULE_LICENSE("GPL v2");
1052