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
1392d9c05cSJakob Hauser * YAS537 MS-3T (2015 Samsung Galaxy S6, Note 5, Galaxy S7)
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 *
2065f79b50SJakob Hauser * Code functions for YAS537 based on Yamaha Android kernel driver.
2165f79b50SJakob Hauser * Copyright (c) 2014 Yamaha Corporation
2265f79b50SJakob Hauser *
23de8860b1SLinus Walleij * Author: Linus Walleij <linus.walleij@linaro.org>
24de8860b1SLinus Walleij */
25de8860b1SLinus Walleij #include <linux/bitfield.h>
26de8860b1SLinus Walleij #include <linux/bitops.h>
27de8860b1SLinus Walleij #include <linux/delay.h>
28de8860b1SLinus Walleij #include <linux/err.h>
29de8860b1SLinus Walleij #include <linux/gpio/consumer.h>
30de8860b1SLinus Walleij #include <linux/i2c.h>
31de8860b1SLinus Walleij #include <linux/module.h>
32de8860b1SLinus Walleij #include <linux/mod_devicetable.h>
33de8860b1SLinus Walleij #include <linux/mutex.h>
34de8860b1SLinus Walleij #include <linux/pm_runtime.h>
35741d1e37SAndy Shevchenko #include <linux/property.h>
36de8860b1SLinus Walleij #include <linux/regmap.h>
37de8860b1SLinus Walleij #include <linux/regulator/consumer.h>
38de8860b1SLinus Walleij #include <linux/random.h>
3965f79b50SJakob Hauser #include <linux/units.h>
40de8860b1SLinus Walleij
41de8860b1SLinus Walleij #include <linux/iio/buffer.h>
42de8860b1SLinus Walleij #include <linux/iio/iio.h>
43de8860b1SLinus Walleij #include <linux/iio/trigger_consumer.h>
44de8860b1SLinus Walleij #include <linux/iio/triggered_buffer.h>
45de8860b1SLinus Walleij
46bb354aebSLinus Walleij #include <asm/unaligned.h>
47bb354aebSLinus Walleij
486e3bfa97SJakob Hauser /* Commonly used registers */
49de8860b1SLinus Walleij #define YAS5XX_DEVICE_ID 0x80
50de8860b1SLinus Walleij #define YAS5XX_MEASURE_DATA 0xB0
51de8860b1SLinus Walleij
526e3bfa97SJakob Hauser /* These registers are used by YAS530, YAS532 and YAS533 */
536e3bfa97SJakob Hauser #define YAS530_ACTUATE_INIT_COIL 0x81
546e3bfa97SJakob Hauser #define YAS530_MEASURE 0x82
556e3bfa97SJakob Hauser #define YAS530_CONFIG 0x83
566e3bfa97SJakob Hauser #define YAS530_MEASURE_INTERVAL 0x84
576e3bfa97SJakob Hauser #define YAS530_OFFSET_X 0x85 /* [-31 .. 31] */
586e3bfa97SJakob Hauser #define YAS530_OFFSET_Y1 0x86 /* [-31 .. 31] */
596e3bfa97SJakob Hauser #define YAS530_OFFSET_Y2 0x87 /* [-31 .. 31] */
606e3bfa97SJakob Hauser #define YAS530_TEST1 0x88
616e3bfa97SJakob Hauser #define YAS530_TEST2 0x89
626e3bfa97SJakob Hauser #define YAS530_CAL 0x90
636e3bfa97SJakob Hauser
6465f79b50SJakob Hauser /* Registers used by YAS537 */
6565f79b50SJakob Hauser #define YAS537_MEASURE 0x81 /* Originally YAS537_REG_CMDR */
6665f79b50SJakob Hauser #define YAS537_CONFIG 0x82 /* Originally YAS537_REG_CONFR */
6765f79b50SJakob Hauser #define YAS537_MEASURE_INTERVAL 0x83 /* Originally YAS537_REG_INTRVLR */
6865f79b50SJakob Hauser #define YAS537_OFFSET_X 0x84 /* Originally YAS537_REG_OXR */
6965f79b50SJakob Hauser #define YAS537_OFFSET_Y1 0x85 /* Originally YAS537_REG_OY1R */
7065f79b50SJakob Hauser #define YAS537_OFFSET_Y2 0x86 /* Originally YAS537_REG_OY2R */
7165f79b50SJakob Hauser #define YAS537_AVR 0x87
7265f79b50SJakob Hauser #define YAS537_HCK 0x88
7365f79b50SJakob Hauser #define YAS537_LCK 0x89
7465f79b50SJakob Hauser #define YAS537_SRST 0x90
7565f79b50SJakob Hauser #define YAS537_ADCCAL 0x91
7665f79b50SJakob Hauser #define YAS537_MTC 0x93
7765f79b50SJakob Hauser #define YAS537_OC 0x9E
7865f79b50SJakob Hauser #define YAS537_TRM 0x9F
7965f79b50SJakob Hauser #define YAS537_CAL 0xC0
8065f79b50SJakob Hauser
81de8860b1SLinus Walleij /* Bits in the YAS5xx config register */
82de8860b1SLinus Walleij #define YAS5XX_CONFIG_INTON BIT(0) /* Interrupt on? */
83de8860b1SLinus Walleij #define YAS5XX_CONFIG_INTHACT BIT(1) /* Interrupt active high? */
84de8860b1SLinus Walleij #define YAS5XX_CONFIG_CCK_MASK GENMASK(4, 2)
85de8860b1SLinus Walleij #define YAS5XX_CONFIG_CCK_SHIFT 2
86de8860b1SLinus Walleij
87de8860b1SLinus Walleij /* Bits in the measure command register */
88de8860b1SLinus Walleij #define YAS5XX_MEASURE_START BIT(0)
89de8860b1SLinus Walleij #define YAS5XX_MEASURE_LDTC BIT(1)
90de8860b1SLinus Walleij #define YAS5XX_MEASURE_FORS BIT(2)
91de8860b1SLinus Walleij #define YAS5XX_MEASURE_DLYMES BIT(4)
9265f79b50SJakob Hauser #define YAS5XX_MEASURE_CONT BIT(5)
93de8860b1SLinus Walleij
94de8860b1SLinus Walleij /* Bits in the measure data register */
95de8860b1SLinus Walleij #define YAS5XX_MEASURE_DATA_BUSY BIT(7)
96de8860b1SLinus Walleij
97de8860b1SLinus Walleij #define YAS530_DEVICE_ID 0x01 /* YAS530 (MS-3E) */
98de8860b1SLinus Walleij #define YAS530_VERSION_A 0 /* YAS530 (MS-3E A) */
99de8860b1SLinus Walleij #define YAS530_VERSION_B 1 /* YAS530B (MS-3E B) */
100de8860b1SLinus Walleij #define YAS530_VERSION_A_COEF 380
101de8860b1SLinus Walleij #define YAS530_VERSION_B_COEF 550
102de8860b1SLinus Walleij #define YAS530_DATA_BITS 12
103de8860b1SLinus Walleij #define YAS530_DATA_CENTER BIT(YAS530_DATA_BITS - 1)
104de8860b1SLinus Walleij #define YAS530_DATA_OVERFLOW (BIT(YAS530_DATA_BITS) - 1)
105de8860b1SLinus Walleij
106de8860b1SLinus Walleij #define YAS532_DEVICE_ID 0x02 /* YAS532/YAS533 (MS-3R/F) */
107de8860b1SLinus Walleij #define YAS532_VERSION_AB 0 /* YAS532/533 AB (MS-3R/F AB) */
108de8860b1SLinus Walleij #define YAS532_VERSION_AC 1 /* YAS532/533 AC (MS-3R/F AC) */
109de8860b1SLinus Walleij #define YAS532_VERSION_AB_COEF 1800
110de8860b1SLinus Walleij #define YAS532_VERSION_AC_COEF_X 850
111de8860b1SLinus Walleij #define YAS532_VERSION_AC_COEF_Y1 750
112de8860b1SLinus Walleij #define YAS532_VERSION_AC_COEF_Y2 750
113de8860b1SLinus Walleij #define YAS532_DATA_BITS 13
114de8860b1SLinus Walleij #define YAS532_DATA_CENTER BIT(YAS532_DATA_BITS - 1)
115de8860b1SLinus Walleij #define YAS532_DATA_OVERFLOW (BIT(YAS532_DATA_BITS) - 1)
116de8860b1SLinus Walleij
117de8860b1SLinus Walleij #define YAS537_DEVICE_ID 0x07 /* YAS537 (MS-3T) */
11865f79b50SJakob Hauser #define YAS537_VERSION_0 0 /* Version naming unknown */
11965f79b50SJakob Hauser #define YAS537_VERSION_1 1 /* Version naming unknown */
12065f79b50SJakob Hauser #define YAS537_MAG_AVERAGE_32_MASK GENMASK(6, 4)
12165f79b50SJakob Hauser #define YAS537_MEASURE_TIME_WORST_US 1500
12265f79b50SJakob Hauser #define YAS537_DEFAULT_SENSOR_DELAY_MS 50
12365f79b50SJakob Hauser #define YAS537_MAG_RCOIL_TIME_US 65
12465f79b50SJakob Hauser #define YAS537_MTC3_MASK_PREP GENMASK(7, 0)
12565f79b50SJakob Hauser #define YAS537_MTC3_MASK_GET GENMASK(7, 5)
12665f79b50SJakob Hauser #define YAS537_MTC3_ADD_BIT BIT(4)
12765f79b50SJakob Hauser #define YAS537_HCK_MASK_PREP GENMASK(4, 0)
12865f79b50SJakob Hauser #define YAS537_HCK_MASK_GET GENMASK(7, 4)
12965f79b50SJakob Hauser #define YAS537_LCK_MASK_PREP GENMASK(4, 0)
13065f79b50SJakob Hauser #define YAS537_LCK_MASK_GET GENMASK(3, 0)
13165f79b50SJakob Hauser #define YAS537_OC_MASK_GET GENMASK(5, 0)
132de8860b1SLinus Walleij
133de8860b1SLinus Walleij /* Turn off device regulators etc after 5 seconds of inactivity */
134de8860b1SLinus Walleij #define YAS5XX_AUTOSUSPEND_DELAY_MS 5000
135de8860b1SLinus Walleij
136a70f60e5SJakob Hauser enum chip_ids {
137a70f60e5SJakob Hauser yas530,
138a70f60e5SJakob Hauser yas532,
139a70f60e5SJakob Hauser yas533,
14065f79b50SJakob Hauser yas537,
141a70f60e5SJakob Hauser };
142a70f60e5SJakob Hauser
143dd9bd44fSJakob Hauser static const int yas530_volatile_reg[] = {
144dd9bd44fSJakob Hauser YAS530_ACTUATE_INIT_COIL,
145dd9bd44fSJakob Hauser YAS530_MEASURE,
146dd9bd44fSJakob Hauser };
147dd9bd44fSJakob Hauser
14865f79b50SJakob Hauser static const int yas537_volatile_reg[] = {
14965f79b50SJakob Hauser YAS537_MEASURE,
15065f79b50SJakob Hauser };
15165f79b50SJakob Hauser
152de8860b1SLinus Walleij struct yas5xx_calibration {
153de8860b1SLinus Walleij /* Linearization calibration x, y1, y2 */
154de8860b1SLinus Walleij s32 r[3];
155de8860b1SLinus Walleij u32 f[3];
156de8860b1SLinus Walleij /* Temperature compensation calibration */
1570ca09faaSJakob Hauser s16 Cx, Cy1, Cy2;
158de8860b1SLinus Walleij /* Misc calibration coefficients */
1590ca09faaSJakob Hauser s8 a2, a3, a4, a6, a7, a8;
1600ca09faaSJakob Hauser s16 a5, a9;
1610ca09faaSJakob Hauser u8 k;
162de8860b1SLinus Walleij /* clock divider */
163de8860b1SLinus Walleij u8 dck;
164de8860b1SLinus Walleij };
165de8860b1SLinus Walleij
166a70f60e5SJakob Hauser struct yas5xx;
167a70f60e5SJakob Hauser
168a70f60e5SJakob Hauser /**
169a70f60e5SJakob Hauser * struct yas5xx_chip_info - device-specific data and function pointers
170a70f60e5SJakob Hauser * @devid: device ID number
171a70f60e5SJakob Hauser * @product_name: product name of the YAS variant
172a70f60e5SJakob Hauser * @version_names: version letters or namings
173dd9bd44fSJakob Hauser * @volatile_reg: device-specific volatile registers
174dd9bd44fSJakob Hauser * @volatile_reg_qty: quantity of device-specific volatile registers
175913fd409SJakob Hauser * @scaling_val2: scaling value for IIO_CHAN_INFO_SCALE
1762d6676ecSJakob Hauser * @t_ref: number of counts at reference temperature 20 °C
1772d6676ecSJakob Hauser * @min_temp_x10: starting point of temperature counting in 1/10:s degrees Celsius
178059ff0f9SJakob Hauser * @get_measure: function pointer to get a measurement
179059ff0f9SJakob Hauser * @get_calibration_data: function pointer to get calibration data
180059ff0f9SJakob Hauser * @dump_calibration: function pointer to dump calibration for debugging
181059ff0f9SJakob Hauser * @measure_offsets: function pointer to measure the offsets
182059ff0f9SJakob Hauser * @power_on: function pointer to power-on procedure
1832d6676ecSJakob Hauser *
1842d6676ecSJakob Hauser * The "t_ref" value for YAS532/533 is known from the Android driver.
18565f79b50SJakob Hauser * For YAS530 and YAS537 it was approximately measured.
1862d6676ecSJakob Hauser *
1872d6676ecSJakob Hauser * The temperatures "min_temp_x10" are derived from the temperature resolutions
1882d6676ecSJakob Hauser * given in the data sheets.
189a70f60e5SJakob Hauser */
190a70f60e5SJakob Hauser struct yas5xx_chip_info {
191a70f60e5SJakob Hauser unsigned int devid;
192ff1c17e9SAndy Shevchenko const char *product_name;
193ff1c17e9SAndy Shevchenko const char *version_names[2];
194dd9bd44fSJakob Hauser const int *volatile_reg;
195dd9bd44fSJakob Hauser int volatile_reg_qty;
196913fd409SJakob Hauser u32 scaling_val2;
1972d6676ecSJakob Hauser u16 t_ref;
1982d6676ecSJakob Hauser s16 min_temp_x10;
199059ff0f9SJakob Hauser int (*get_measure)(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo);
200059ff0f9SJakob Hauser int (*get_calibration_data)(struct yas5xx *yas5xx);
201059ff0f9SJakob Hauser void (*dump_calibration)(struct yas5xx *yas5xx);
202059ff0f9SJakob Hauser int (*measure_offsets)(struct yas5xx *yas5xx);
203059ff0f9SJakob Hauser int (*power_on)(struct yas5xx *yas5xx);
204a70f60e5SJakob Hauser };
205a70f60e5SJakob Hauser
206de8860b1SLinus Walleij /**
207de8860b1SLinus Walleij * struct yas5xx - state container for the YAS5xx driver
208de8860b1SLinus Walleij * @dev: parent device pointer
209059ff0f9SJakob Hauser * @chip_info: device-specific data and function pointers
210de8860b1SLinus Walleij * @version: device version
211de8860b1SLinus Walleij * @calibration: calibration settings from the OTP storage
212de8860b1SLinus Walleij * @hard_offsets: offsets for each axis measured with initcoil actuated
213de8860b1SLinus Walleij * @orientation: mounting matrix, flipped axis etc
214de8860b1SLinus Walleij * @map: regmap to access the YAX5xx registers over I2C
215de8860b1SLinus Walleij * @regs: the vdd and vddio power regulators
216de8860b1SLinus Walleij * @reset: optional GPIO line used for handling RESET
217de8860b1SLinus Walleij * @lock: locks the magnetometer for exclusive use during a measurement (which
218de8860b1SLinus Walleij * involves several register transactions so the regmap lock is not enough)
219de8860b1SLinus Walleij * so that measurements get serialized in a first-come-first serve manner
220de8860b1SLinus Walleij * @scan: naturally aligned measurements
221de8860b1SLinus Walleij */
222de8860b1SLinus Walleij struct yas5xx {
223de8860b1SLinus Walleij struct device *dev;
224a70f60e5SJakob Hauser const struct yas5xx_chip_info *chip_info;
225de8860b1SLinus Walleij unsigned int version;
226de8860b1SLinus Walleij struct yas5xx_calibration calibration;
227e137fafcSJakob Hauser s8 hard_offsets[3];
228de8860b1SLinus Walleij struct iio_mount_matrix orientation;
229de8860b1SLinus Walleij struct regmap *map;
230de8860b1SLinus Walleij struct regulator_bulk_data regs[2];
231de8860b1SLinus Walleij struct gpio_desc *reset;
232de8860b1SLinus Walleij struct mutex lock;
233de8860b1SLinus Walleij /*
234de8860b1SLinus Walleij * The scanout is 4 x 32 bits in CPU endianness.
235de8860b1SLinus Walleij * Ensure timestamp is naturally aligned
236de8860b1SLinus Walleij */
237de8860b1SLinus Walleij struct {
238de8860b1SLinus Walleij s32 channels[4];
239de8860b1SLinus Walleij s64 ts __aligned(8);
240de8860b1SLinus Walleij } scan;
241de8860b1SLinus Walleij };
242de8860b1SLinus Walleij
243de8860b1SLinus Walleij /* On YAS530 the x, y1 and y2 values are 12 bits */
yas530_extract_axis(u8 * data)244de8860b1SLinus Walleij static u16 yas530_extract_axis(u8 *data)
245de8860b1SLinus Walleij {
246de8860b1SLinus Walleij u16 val;
247de8860b1SLinus Walleij
248de8860b1SLinus Walleij /*
249de8860b1SLinus Walleij * These are the bits used in a 16bit word:
250de8860b1SLinus Walleij * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
251de8860b1SLinus Walleij * x x x x x x x x x x x x
252de8860b1SLinus Walleij */
253de8860b1SLinus Walleij val = get_unaligned_be16(&data[0]);
254de8860b1SLinus Walleij val = FIELD_GET(GENMASK(14, 3), val);
255de8860b1SLinus Walleij return val;
256de8860b1SLinus Walleij }
257de8860b1SLinus Walleij
258de8860b1SLinus Walleij /* On YAS532 the x, y1 and y2 values are 13 bits */
yas532_extract_axis(u8 * data)259de8860b1SLinus Walleij static u16 yas532_extract_axis(u8 *data)
260de8860b1SLinus Walleij {
261de8860b1SLinus Walleij u16 val;
262de8860b1SLinus Walleij
263de8860b1SLinus Walleij /*
264de8860b1SLinus Walleij * These are the bits used in a 16bit word:
265de8860b1SLinus Walleij * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
266de8860b1SLinus Walleij * x x x x x x x x x x x x x
267de8860b1SLinus Walleij */
268de8860b1SLinus Walleij val = get_unaligned_be16(&data[0]);
269de8860b1SLinus Walleij val = FIELD_GET(GENMASK(14, 2), val);
270de8860b1SLinus Walleij return val;
271de8860b1SLinus Walleij }
272de8860b1SLinus Walleij
273de8860b1SLinus Walleij /**
2746e3bfa97SJakob Hauser * yas530_measure() - Make a measure from the hardware
275de8860b1SLinus Walleij * @yas5xx: The device state
276de8860b1SLinus Walleij * @t: the raw temperature measurement
277de8860b1SLinus Walleij * @x: the raw x axis measurement
278de8860b1SLinus Walleij * @y1: the y1 axis measurement
279de8860b1SLinus Walleij * @y2: the y2 axis measurement
280de8860b1SLinus Walleij * @return: 0 on success or error code
2816e3bfa97SJakob Hauser *
2826e3bfa97SJakob Hauser * Used by YAS530, YAS532 and YAS533.
283de8860b1SLinus Walleij */
yas530_measure(struct yas5xx * yas5xx,u16 * t,u16 * x,u16 * y1,u16 * y2)2846e3bfa97SJakob Hauser static int yas530_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)
285de8860b1SLinus Walleij {
286a70f60e5SJakob Hauser const struct yas5xx_chip_info *ci = yas5xx->chip_info;
287de8860b1SLinus Walleij unsigned int busy;
288de8860b1SLinus Walleij u8 data[8];
289de8860b1SLinus Walleij int ret;
290de8860b1SLinus Walleij u16 val;
291de8860b1SLinus Walleij
292de8860b1SLinus Walleij mutex_lock(&yas5xx->lock);
2936e3bfa97SJakob Hauser ret = regmap_write(yas5xx->map, YAS530_MEASURE, YAS5XX_MEASURE_START);
294de8860b1SLinus Walleij if (ret < 0)
295de8860b1SLinus Walleij goto out_unlock;
296de8860b1SLinus Walleij
297de8860b1SLinus Walleij /*
298de8860b1SLinus Walleij * Typical time to measure 1500 us, max 2000 us so wait min 500 us
299de8860b1SLinus Walleij * and at most 20000 us (one magnitude more than the datsheet max)
300de8860b1SLinus Walleij * before timeout.
301de8860b1SLinus Walleij */
302de8860b1SLinus Walleij ret = regmap_read_poll_timeout(yas5xx->map, YAS5XX_MEASURE_DATA, busy,
303de8860b1SLinus Walleij !(busy & YAS5XX_MEASURE_DATA_BUSY),
304de8860b1SLinus Walleij 500, 20000);
305de8860b1SLinus Walleij if (ret) {
306de8860b1SLinus Walleij dev_err(yas5xx->dev, "timeout waiting for measurement\n");
307de8860b1SLinus Walleij goto out_unlock;
308de8860b1SLinus Walleij }
309de8860b1SLinus Walleij
310de8860b1SLinus Walleij ret = regmap_bulk_read(yas5xx->map, YAS5XX_MEASURE_DATA,
311de8860b1SLinus Walleij data, sizeof(data));
312de8860b1SLinus Walleij if (ret)
313de8860b1SLinus Walleij goto out_unlock;
314de8860b1SLinus Walleij
315de8860b1SLinus Walleij mutex_unlock(&yas5xx->lock);
316de8860b1SLinus Walleij
317a70f60e5SJakob Hauser switch (ci->devid) {
318de8860b1SLinus Walleij case YAS530_DEVICE_ID:
319de8860b1SLinus Walleij /*
320de8860b1SLinus Walleij * The t value is 9 bits in big endian format
321de8860b1SLinus Walleij * These are the bits used in a 16bit word:
322de8860b1SLinus Walleij * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
323de8860b1SLinus Walleij * x x x x x x x x x
324de8860b1SLinus Walleij */
325de8860b1SLinus Walleij val = get_unaligned_be16(&data[0]);
326de8860b1SLinus Walleij val = FIELD_GET(GENMASK(14, 6), val);
327de8860b1SLinus Walleij *t = val;
328de8860b1SLinus Walleij *x = yas530_extract_axis(&data[2]);
329de8860b1SLinus Walleij *y1 = yas530_extract_axis(&data[4]);
330de8860b1SLinus Walleij *y2 = yas530_extract_axis(&data[6]);
331de8860b1SLinus Walleij break;
332de8860b1SLinus Walleij case YAS532_DEVICE_ID:
333de8860b1SLinus Walleij /*
334de8860b1SLinus Walleij * The t value is 10 bits in big endian format
335de8860b1SLinus Walleij * These are the bits used in a 16bit word:
336de8860b1SLinus Walleij * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
337de8860b1SLinus Walleij * x x x x x x x x x x
338de8860b1SLinus Walleij */
339de8860b1SLinus Walleij val = get_unaligned_be16(&data[0]);
340de8860b1SLinus Walleij val = FIELD_GET(GENMASK(14, 5), val);
341de8860b1SLinus Walleij *t = val;
342de8860b1SLinus Walleij *x = yas532_extract_axis(&data[2]);
343de8860b1SLinus Walleij *y1 = yas532_extract_axis(&data[4]);
344de8860b1SLinus Walleij *y2 = yas532_extract_axis(&data[6]);
345de8860b1SLinus Walleij break;
346de8860b1SLinus Walleij default:
347de8860b1SLinus Walleij dev_err(yas5xx->dev, "unknown data format\n");
348de8860b1SLinus Walleij ret = -EINVAL;
349de8860b1SLinus Walleij break;
350de8860b1SLinus Walleij }
351de8860b1SLinus Walleij
352de8860b1SLinus Walleij return ret;
353de8860b1SLinus Walleij
354de8860b1SLinus Walleij out_unlock:
355de8860b1SLinus Walleij mutex_unlock(&yas5xx->lock);
356de8860b1SLinus Walleij return ret;
357de8860b1SLinus Walleij }
358de8860b1SLinus Walleij
35965f79b50SJakob Hauser /**
36065f79b50SJakob Hauser * yas537_measure() - Make a measure from the hardware
36165f79b50SJakob Hauser * @yas5xx: The device state
36265f79b50SJakob Hauser * @t: the raw temperature measurement
36365f79b50SJakob Hauser * @x: the raw x axis measurement
36465f79b50SJakob Hauser * @y1: the y1 axis measurement
36565f79b50SJakob Hauser * @y2: the y2 axis measurement
36665f79b50SJakob Hauser * @return: 0 on success or error code
36765f79b50SJakob Hauser */
yas537_measure(struct yas5xx * yas5xx,u16 * t,u16 * x,u16 * y1,u16 * y2)36865f79b50SJakob Hauser static int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)
369de8860b1SLinus Walleij {
370de8860b1SLinus Walleij struct yas5xx_calibration *c = &yas5xx->calibration;
37165f79b50SJakob Hauser unsigned int busy;
37265f79b50SJakob Hauser u8 data[8];
37365f79b50SJakob Hauser u16 xy1y2[3];
37465f79b50SJakob Hauser s32 h[3], s[3];
375*67e97213SJakob Hauser int half_range = BIT(13);
37665f79b50SJakob Hauser int i, ret;
37765f79b50SJakob Hauser
37865f79b50SJakob Hauser mutex_lock(&yas5xx->lock);
37965f79b50SJakob Hauser
38065f79b50SJakob Hauser /* Contrary to YAS530/532, also a "cont" bit is set, meaning unknown */
38165f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_MEASURE, YAS5XX_MEASURE_START |
38265f79b50SJakob Hauser YAS5XX_MEASURE_CONT);
38365f79b50SJakob Hauser if (ret < 0)
38465f79b50SJakob Hauser goto out_unlock;
38565f79b50SJakob Hauser
38665f79b50SJakob Hauser /* Use same timeout like YAS530/532 but the bit is in data row 2 */
38765f79b50SJakob Hauser ret = regmap_read_poll_timeout(yas5xx->map, YAS5XX_MEASURE_DATA + 2, busy,
38865f79b50SJakob Hauser !(busy & YAS5XX_MEASURE_DATA_BUSY),
38965f79b50SJakob Hauser 500, 20000);
39065f79b50SJakob Hauser if (ret) {
39165f79b50SJakob Hauser dev_err(yas5xx->dev, "timeout waiting for measurement\n");
39265f79b50SJakob Hauser goto out_unlock;
39365f79b50SJakob Hauser }
39465f79b50SJakob Hauser
39565f79b50SJakob Hauser ret = regmap_bulk_read(yas5xx->map, YAS5XX_MEASURE_DATA,
39665f79b50SJakob Hauser data, sizeof(data));
39765f79b50SJakob Hauser if (ret)
39865f79b50SJakob Hauser goto out_unlock;
39965f79b50SJakob Hauser
40065f79b50SJakob Hauser mutex_unlock(&yas5xx->lock);
40165f79b50SJakob Hauser
40265f79b50SJakob Hauser *t = get_unaligned_be16(&data[0]);
40365f79b50SJakob Hauser xy1y2[0] = FIELD_GET(GENMASK(13, 0), get_unaligned_be16(&data[2]));
40465f79b50SJakob Hauser xy1y2[1] = get_unaligned_be16(&data[4]);
40565f79b50SJakob Hauser xy1y2[2] = get_unaligned_be16(&data[6]);
40665f79b50SJakob Hauser
40765f79b50SJakob Hauser /* The second version of YAS537 needs to include calibration coefficients */
40865f79b50SJakob Hauser if (yas5xx->version == YAS537_VERSION_1) {
40965f79b50SJakob Hauser for (i = 0; i < 3; i++)
410*67e97213SJakob Hauser s[i] = xy1y2[i] - half_range;
411*67e97213SJakob Hauser h[0] = (c->k * (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / half_range;
412*67e97213SJakob Hauser h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / half_range;
413*67e97213SJakob Hauser h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / half_range;
41465f79b50SJakob Hauser for (i = 0; i < 3; i++) {
415*67e97213SJakob Hauser h[i] = clamp(h[i], -half_range, half_range - 1);
416*67e97213SJakob Hauser xy1y2[i] = h[i] + half_range;
41765f79b50SJakob Hauser }
41865f79b50SJakob Hauser }
41965f79b50SJakob Hauser
42065f79b50SJakob Hauser *x = xy1y2[0];
42165f79b50SJakob Hauser *y1 = xy1y2[1];
42265f79b50SJakob Hauser *y2 = xy1y2[2];
42365f79b50SJakob Hauser
42465f79b50SJakob Hauser return 0;
42565f79b50SJakob Hauser
42665f79b50SJakob Hauser out_unlock:
42765f79b50SJakob Hauser mutex_unlock(&yas5xx->lock);
42865f79b50SJakob Hauser return ret;
42965f79b50SJakob Hauser }
43065f79b50SJakob Hauser
4316e3bfa97SJakob Hauser /* Used by YAS530, YAS532 and YAS533 */
yas530_linearize(struct yas5xx * yas5xx,u16 val,int axis)4326e3bfa97SJakob Hauser static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis)
433de8860b1SLinus Walleij {
434a70f60e5SJakob Hauser const struct yas5xx_chip_info *ci = yas5xx->chip_info;
435de8860b1SLinus Walleij struct yas5xx_calibration *c = &yas5xx->calibration;
436de8860b1SLinus Walleij static const s32 yas532ac_coef[] = {
437de8860b1SLinus Walleij YAS532_VERSION_AC_COEF_X,
438de8860b1SLinus Walleij YAS532_VERSION_AC_COEF_Y1,
439de8860b1SLinus Walleij YAS532_VERSION_AC_COEF_Y2,
440de8860b1SLinus Walleij };
441de8860b1SLinus Walleij s32 coef;
442de8860b1SLinus Walleij
443de8860b1SLinus Walleij /* Select coefficients */
444a70f60e5SJakob Hauser switch (ci->devid) {
445de8860b1SLinus Walleij case YAS530_DEVICE_ID:
446de8860b1SLinus Walleij if (yas5xx->version == YAS530_VERSION_A)
447de8860b1SLinus Walleij coef = YAS530_VERSION_A_COEF;
448de8860b1SLinus Walleij else
449de8860b1SLinus Walleij coef = YAS530_VERSION_B_COEF;
450de8860b1SLinus Walleij break;
451de8860b1SLinus Walleij case YAS532_DEVICE_ID:
452de8860b1SLinus Walleij if (yas5xx->version == YAS532_VERSION_AB)
453de8860b1SLinus Walleij coef = YAS532_VERSION_AB_COEF;
454de8860b1SLinus Walleij else
455de8860b1SLinus Walleij /* Elaborate coefficients */
456de8860b1SLinus Walleij coef = yas532ac_coef[axis];
457de8860b1SLinus Walleij break;
458de8860b1SLinus Walleij default:
459de8860b1SLinus Walleij dev_err(yas5xx->dev, "unknown device type\n");
460de8860b1SLinus Walleij return val;
461de8860b1SLinus Walleij }
462de8860b1SLinus Walleij /*
463de8860b1SLinus Walleij * Linearization formula:
464de8860b1SLinus Walleij *
465de8860b1SLinus Walleij * x' = x - (3721 + 50 * f) + (xoffset - r) * c
466de8860b1SLinus Walleij *
467de8860b1SLinus Walleij * Where f and r are calibration values, c is a per-device
468de8860b1SLinus Walleij * and sometimes per-axis coefficient.
469de8860b1SLinus Walleij */
470de8860b1SLinus Walleij return val - (3721 + 50 * c->f[axis]) +
471de8860b1SLinus Walleij (yas5xx->hard_offsets[axis] - c->r[axis]) * coef;
472de8860b1SLinus Walleij }
473de8860b1SLinus Walleij
yas5xx_calc_temperature(struct yas5xx * yas5xx,u16 t)4742d6676ecSJakob Hauser static s32 yas5xx_calc_temperature(struct yas5xx *yas5xx, u16 t)
4752d6676ecSJakob Hauser {
4762d6676ecSJakob Hauser const struct yas5xx_chip_info *ci = yas5xx->chip_info;
4772d6676ecSJakob Hauser s32 to;
4782d6676ecSJakob Hauser u16 t_ref;
4792d6676ecSJakob Hauser s16 min_temp_x10;
4802d6676ecSJakob Hauser int ref_temp_x10;
4812d6676ecSJakob Hauser
4822d6676ecSJakob Hauser t_ref = ci->t_ref;
4832d6676ecSJakob Hauser min_temp_x10 = ci->min_temp_x10;
4842d6676ecSJakob Hauser ref_temp_x10 = 200;
4852d6676ecSJakob Hauser
4862d6676ecSJakob Hauser to = (min_temp_x10 + ((ref_temp_x10 - min_temp_x10) * t / t_ref)) * 100;
4872d6676ecSJakob Hauser return to;
4882d6676ecSJakob Hauser }
4892d6676ecSJakob Hauser
490de8860b1SLinus Walleij /**
4916e3bfa97SJakob Hauser * yas530_get_measure() - Measure a sample of all axis and process
492de8860b1SLinus Walleij * @yas5xx: The device state
493de8860b1SLinus Walleij * @to: Temperature out
494de8860b1SLinus Walleij * @xo: X axis out
495de8860b1SLinus Walleij * @yo: Y axis out
496de8860b1SLinus Walleij * @zo: Z axis out
497de8860b1SLinus Walleij * @return: 0 on success or error code
498de8860b1SLinus Walleij *
4996e3bfa97SJakob Hauser * Used by YAS530, YAS532 and YAS533.
500de8860b1SLinus Walleij */
yas530_get_measure(struct yas5xx * yas5xx,s32 * to,s32 * xo,s32 * yo,s32 * zo)5016e3bfa97SJakob Hauser static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
502de8860b1SLinus Walleij {
503a70f60e5SJakob Hauser const struct yas5xx_chip_info *ci = yas5xx->chip_info;
504de8860b1SLinus Walleij struct yas5xx_calibration *c = &yas5xx->calibration;
5052d6676ecSJakob Hauser u16 t_ref, t_comp, t, x, y1, y2;
50692d9c05cSJakob Hauser /* These are signed x, signed y1 etc */
507de8860b1SLinus Walleij s32 sx, sy1, sy2, sy, sz;
508de8860b1SLinus Walleij int ret;
509de8860b1SLinus Walleij
510de8860b1SLinus Walleij /* We first get raw data that needs to be translated to [x,y,z] */
5116e3bfa97SJakob Hauser ret = yas530_measure(yas5xx, &t, &x, &y1, &y2);
512de8860b1SLinus Walleij if (ret)
513de8860b1SLinus Walleij return ret;
514de8860b1SLinus Walleij
515de8860b1SLinus Walleij /* Do some linearization if available */
5166e3bfa97SJakob Hauser sx = yas530_linearize(yas5xx, x, 0);
5176e3bfa97SJakob Hauser sy1 = yas530_linearize(yas5xx, y1, 1);
5186e3bfa97SJakob Hauser sy2 = yas530_linearize(yas5xx, y2, 2);
519de8860b1SLinus Walleij
5202d6676ecSJakob Hauser /*
5212d6676ecSJakob Hauser * Set the temperature for compensation (unit: counts):
5222d6676ecSJakob Hauser * YAS532/YAS533 version AC uses the temperature deviation as a
5232d6676ecSJakob Hauser * multiplier. YAS530 and YAS532 version AB use solely the t value.
5242d6676ecSJakob Hauser */
5252d6676ecSJakob Hauser t_ref = ci->t_ref;
526a70f60e5SJakob Hauser if (ci->devid == YAS532_DEVICE_ID &&
5278239f904SJakob Hauser yas5xx->version == YAS532_VERSION_AC) {
5282d6676ecSJakob Hauser t_comp = t - t_ref;
5298239f904SJakob Hauser } else {
5302d6676ecSJakob Hauser t_comp = t;
5312d6676ecSJakob Hauser }
532de8860b1SLinus Walleij
533de8860b1SLinus Walleij /*
534de8860b1SLinus Walleij * Temperature compensation for x, y1, y2 respectively:
535de8860b1SLinus Walleij *
5362d6676ecSJakob Hauser * Cx * t_comp
5372d6676ecSJakob Hauser * x' = x - -----------
538de8860b1SLinus Walleij * 100
539de8860b1SLinus Walleij */
5402d6676ecSJakob Hauser sx = sx - (c->Cx * t_comp) / 100;
5412d6676ecSJakob Hauser sy1 = sy1 - (c->Cy1 * t_comp) / 100;
5422d6676ecSJakob Hauser sy2 = sy2 - (c->Cy2 * t_comp) / 100;
543de8860b1SLinus Walleij
544de8860b1SLinus Walleij /*
545de8860b1SLinus Walleij * Break y1 and y2 into y and z, y1 and y2 are apparently encoding
546de8860b1SLinus Walleij * y and z.
547de8860b1SLinus Walleij */
548de8860b1SLinus Walleij sy = sy1 - sy2;
549de8860b1SLinus Walleij sz = -sy1 - sy2;
550de8860b1SLinus Walleij
5512d6676ecSJakob Hauser /* Calculate temperature readout */
5522d6676ecSJakob Hauser *to = yas5xx_calc_temperature(yas5xx, t);
5538239f904SJakob Hauser
554de8860b1SLinus Walleij /*
555de8860b1SLinus Walleij * Calibrate [x,y,z] with some formulas like this:
556de8860b1SLinus Walleij *
557de8860b1SLinus Walleij * 100 * x + a_2 * y + a_3 * z
558de8860b1SLinus Walleij * x' = k * ---------------------------
559de8860b1SLinus Walleij * 10
560de8860b1SLinus Walleij *
561de8860b1SLinus Walleij * a_4 * x + a_5 * y + a_6 * z
562de8860b1SLinus Walleij * y' = k * ---------------------------
563de8860b1SLinus Walleij * 10
564de8860b1SLinus Walleij *
565de8860b1SLinus Walleij * a_7 * x + a_8 * y + a_9 * z
566de8860b1SLinus Walleij * z' = k * ---------------------------
567de8860b1SLinus Walleij * 10
568de8860b1SLinus Walleij */
569de8860b1SLinus Walleij *xo = c->k * ((100 * sx + c->a2 * sy + c->a3 * sz) / 10);
570de8860b1SLinus Walleij *yo = c->k * ((c->a4 * sx + c->a5 * sy + c->a6 * sz) / 10);
571de8860b1SLinus Walleij *zo = c->k * ((c->a7 * sx + c->a8 * sy + c->a9 * sz) / 10);
572de8860b1SLinus Walleij
573de8860b1SLinus Walleij return 0;
574de8860b1SLinus Walleij }
575de8860b1SLinus Walleij
57665f79b50SJakob Hauser /**
57765f79b50SJakob Hauser * yas537_get_measure() - Measure a sample of all axis and process
57865f79b50SJakob Hauser * @yas5xx: The device state
57965f79b50SJakob Hauser * @to: Temperature out
58065f79b50SJakob Hauser * @xo: X axis out
58165f79b50SJakob Hauser * @yo: Y axis out
58265f79b50SJakob Hauser * @zo: Z axis out
58365f79b50SJakob Hauser * @return: 0 on success or error code
58465f79b50SJakob Hauser */
yas537_get_measure(struct yas5xx * yas5xx,s32 * to,s32 * xo,s32 * yo,s32 * zo)58565f79b50SJakob Hauser static int yas537_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
58665f79b50SJakob Hauser {
58765f79b50SJakob Hauser u16 t, x, y1, y2;
58865f79b50SJakob Hauser int ret;
58965f79b50SJakob Hauser
59065f79b50SJakob Hauser /* We first get raw data that needs to be translated to [x,y,z] */
59165f79b50SJakob Hauser ret = yas537_measure(yas5xx, &t, &x, &y1, &y2);
59265f79b50SJakob Hauser if (ret)
59365f79b50SJakob Hauser return ret;
59465f79b50SJakob Hauser
59565f79b50SJakob Hauser /* Calculate temperature readout */
59665f79b50SJakob Hauser *to = yas5xx_calc_temperature(yas5xx, t);
59765f79b50SJakob Hauser
59865f79b50SJakob Hauser /*
59965f79b50SJakob Hauser * Unfortunately, no linearization or temperature compensation formulas
60065f79b50SJakob Hauser * are known for YAS537.
60165f79b50SJakob Hauser */
60265f79b50SJakob Hauser
60365f79b50SJakob Hauser /* Calculate x, y, z from x, y1, y2 */
60465f79b50SJakob Hauser *xo = (x - BIT(13)) * 300;
60565f79b50SJakob Hauser *yo = (y1 - y2) * 1732 / 10;
60665f79b50SJakob Hauser *zo = (-y1 - y2 + BIT(14)) * 300;
60765f79b50SJakob Hauser
60865f79b50SJakob Hauser return 0;
60965f79b50SJakob Hauser }
61065f79b50SJakob Hauser
yas5xx_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)611de8860b1SLinus Walleij static int yas5xx_read_raw(struct iio_dev *indio_dev,
612de8860b1SLinus Walleij struct iio_chan_spec const *chan,
613de8860b1SLinus Walleij int *val, int *val2,
614de8860b1SLinus Walleij long mask)
615de8860b1SLinus Walleij {
616de8860b1SLinus Walleij struct yas5xx *yas5xx = iio_priv(indio_dev);
617a70f60e5SJakob Hauser const struct yas5xx_chip_info *ci = yas5xx->chip_info;
618de8860b1SLinus Walleij s32 t, x, y, z;
619de8860b1SLinus Walleij int ret;
620de8860b1SLinus Walleij
621de8860b1SLinus Walleij switch (mask) {
6228239f904SJakob Hauser case IIO_CHAN_INFO_PROCESSED:
623de8860b1SLinus Walleij case IIO_CHAN_INFO_RAW:
624de8860b1SLinus Walleij pm_runtime_get_sync(yas5xx->dev);
625059ff0f9SJakob Hauser ret = ci->get_measure(yas5xx, &t, &x, &y, &z);
626de8860b1SLinus Walleij pm_runtime_mark_last_busy(yas5xx->dev);
627de8860b1SLinus Walleij pm_runtime_put_autosuspend(yas5xx->dev);
628de8860b1SLinus Walleij if (ret)
629de8860b1SLinus Walleij return ret;
630de8860b1SLinus Walleij switch (chan->address) {
631de8860b1SLinus Walleij case 0:
632de8860b1SLinus Walleij *val = t;
633de8860b1SLinus Walleij break;
634de8860b1SLinus Walleij case 1:
635de8860b1SLinus Walleij *val = x;
636de8860b1SLinus Walleij break;
637de8860b1SLinus Walleij case 2:
638de8860b1SLinus Walleij *val = y;
639de8860b1SLinus Walleij break;
640de8860b1SLinus Walleij case 3:
641de8860b1SLinus Walleij *val = z;
642de8860b1SLinus Walleij break;
643de8860b1SLinus Walleij default:
644de8860b1SLinus Walleij dev_err(yas5xx->dev, "unknown channel\n");
645de8860b1SLinus Walleij return -EINVAL;
646de8860b1SLinus Walleij }
647de8860b1SLinus Walleij return IIO_VAL_INT;
648de8860b1SLinus Walleij case IIO_CHAN_INFO_SCALE:
649de8860b1SLinus Walleij *val = 1;
650913fd409SJakob Hauser *val2 = ci->scaling_val2;
651de8860b1SLinus Walleij return IIO_VAL_FRACTIONAL;
652de8860b1SLinus Walleij default:
653de8860b1SLinus Walleij /* Unknown request */
654de8860b1SLinus Walleij return -EINVAL;
655de8860b1SLinus Walleij }
656de8860b1SLinus Walleij }
657de8860b1SLinus Walleij
yas5xx_fill_buffer(struct iio_dev * indio_dev)658de8860b1SLinus Walleij static void yas5xx_fill_buffer(struct iio_dev *indio_dev)
659de8860b1SLinus Walleij {
660de8860b1SLinus Walleij struct yas5xx *yas5xx = iio_priv(indio_dev);
661059ff0f9SJakob Hauser const struct yas5xx_chip_info *ci = yas5xx->chip_info;
662de8860b1SLinus Walleij s32 t, x, y, z;
663de8860b1SLinus Walleij int ret;
664de8860b1SLinus Walleij
665de8860b1SLinus Walleij pm_runtime_get_sync(yas5xx->dev);
666059ff0f9SJakob Hauser ret = ci->get_measure(yas5xx, &t, &x, &y, &z);
667de8860b1SLinus Walleij pm_runtime_mark_last_busy(yas5xx->dev);
668de8860b1SLinus Walleij pm_runtime_put_autosuspend(yas5xx->dev);
669de8860b1SLinus Walleij if (ret) {
670de8860b1SLinus Walleij dev_err(yas5xx->dev, "error refilling buffer\n");
671de8860b1SLinus Walleij return;
672de8860b1SLinus Walleij }
673de8860b1SLinus Walleij yas5xx->scan.channels[0] = t;
674de8860b1SLinus Walleij yas5xx->scan.channels[1] = x;
675de8860b1SLinus Walleij yas5xx->scan.channels[2] = y;
676de8860b1SLinus Walleij yas5xx->scan.channels[3] = z;
677de8860b1SLinus Walleij iio_push_to_buffers_with_timestamp(indio_dev, &yas5xx->scan,
678de8860b1SLinus Walleij iio_get_time_ns(indio_dev));
679de8860b1SLinus Walleij }
680de8860b1SLinus Walleij
yas5xx_handle_trigger(int irq,void * p)681de8860b1SLinus Walleij static irqreturn_t yas5xx_handle_trigger(int irq, void *p)
682de8860b1SLinus Walleij {
683de8860b1SLinus Walleij const struct iio_poll_func *pf = p;
684de8860b1SLinus Walleij struct iio_dev *indio_dev = pf->indio_dev;
685de8860b1SLinus Walleij
686de8860b1SLinus Walleij yas5xx_fill_buffer(indio_dev);
687de8860b1SLinus Walleij iio_trigger_notify_done(indio_dev->trig);
688de8860b1SLinus Walleij
689de8860b1SLinus Walleij return IRQ_HANDLED;
690de8860b1SLinus Walleij }
691de8860b1SLinus Walleij
692de8860b1SLinus Walleij
693de8860b1SLinus Walleij static const struct iio_mount_matrix *
yas5xx_get_mount_matrix(const struct iio_dev * indio_dev,const struct iio_chan_spec * chan)694de8860b1SLinus Walleij yas5xx_get_mount_matrix(const struct iio_dev *indio_dev,
695de8860b1SLinus Walleij const struct iio_chan_spec *chan)
696de8860b1SLinus Walleij {
697de8860b1SLinus Walleij struct yas5xx *yas5xx = iio_priv(indio_dev);
698de8860b1SLinus Walleij
699de8860b1SLinus Walleij return &yas5xx->orientation;
700de8860b1SLinus Walleij }
701de8860b1SLinus Walleij
702de8860b1SLinus Walleij static const struct iio_chan_spec_ext_info yas5xx_ext_info[] = {
703de8860b1SLinus Walleij IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, yas5xx_get_mount_matrix),
704de8860b1SLinus Walleij { }
705de8860b1SLinus Walleij };
706de8860b1SLinus Walleij
707de8860b1SLinus Walleij #define YAS5XX_AXIS_CHANNEL(axis, index) \
708de8860b1SLinus Walleij { \
709de8860b1SLinus Walleij .type = IIO_MAGN, \
710de8860b1SLinus Walleij .modified = 1, \
711de8860b1SLinus Walleij .channel2 = IIO_MOD_##axis, \
712de8860b1SLinus Walleij .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
713de8860b1SLinus Walleij BIT(IIO_CHAN_INFO_SCALE), \
714de8860b1SLinus Walleij .ext_info = yas5xx_ext_info, \
715de8860b1SLinus Walleij .address = index, \
716de8860b1SLinus Walleij .scan_index = index, \
717de8860b1SLinus Walleij .scan_type = { \
718de8860b1SLinus Walleij .sign = 's', \
719de8860b1SLinus Walleij .realbits = 32, \
720de8860b1SLinus Walleij .storagebits = 32, \
721de8860b1SLinus Walleij .endianness = IIO_CPU, \
722de8860b1SLinus Walleij }, \
723de8860b1SLinus Walleij }
724de8860b1SLinus Walleij
725de8860b1SLinus Walleij static const struct iio_chan_spec yas5xx_channels[] = {
726de8860b1SLinus Walleij {
727de8860b1SLinus Walleij .type = IIO_TEMP,
728de8860b1SLinus Walleij .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
729de8860b1SLinus Walleij .address = 0,
730de8860b1SLinus Walleij .scan_index = 0,
731de8860b1SLinus Walleij .scan_type = {
7328239f904SJakob Hauser .sign = 's',
733de8860b1SLinus Walleij .realbits = 32,
734de8860b1SLinus Walleij .storagebits = 32,
735de8860b1SLinus Walleij .endianness = IIO_CPU,
736de8860b1SLinus Walleij },
737de8860b1SLinus Walleij },
738de8860b1SLinus Walleij YAS5XX_AXIS_CHANNEL(X, 1),
739de8860b1SLinus Walleij YAS5XX_AXIS_CHANNEL(Y, 2),
740de8860b1SLinus Walleij YAS5XX_AXIS_CHANNEL(Z, 3),
741de8860b1SLinus Walleij IIO_CHAN_SOFT_TIMESTAMP(4),
742de8860b1SLinus Walleij };
743de8860b1SLinus Walleij
744de8860b1SLinus Walleij static const unsigned long yas5xx_scan_masks[] = { GENMASK(3, 0), 0 };
745de8860b1SLinus Walleij
746de8860b1SLinus Walleij static const struct iio_info yas5xx_info = {
747de8860b1SLinus Walleij .read_raw = &yas5xx_read_raw,
748de8860b1SLinus Walleij };
749de8860b1SLinus Walleij
yas5xx_volatile_reg(struct device * dev,unsigned int reg)750de8860b1SLinus Walleij static bool yas5xx_volatile_reg(struct device *dev, unsigned int reg)
751de8860b1SLinus Walleij {
752dd9bd44fSJakob Hauser struct iio_dev *indio_dev = dev_get_drvdata(dev);
753dd9bd44fSJakob Hauser struct yas5xx *yas5xx = iio_priv(indio_dev);
754dd9bd44fSJakob Hauser const struct yas5xx_chip_info *ci = yas5xx->chip_info;
755dd9bd44fSJakob Hauser int reg_qty;
756dd9bd44fSJakob Hauser int i;
757dd9bd44fSJakob Hauser
758dd9bd44fSJakob Hauser if (reg >= YAS5XX_MEASURE_DATA && reg < YAS5XX_MEASURE_DATA + 8)
759dd9bd44fSJakob Hauser return true;
760dd9bd44fSJakob Hauser
761dd9bd44fSJakob Hauser /*
762dd9bd44fSJakob Hauser * YAS versions share different registers on the same address,
763dd9bd44fSJakob Hauser * need to differentiate.
764dd9bd44fSJakob Hauser */
765dd9bd44fSJakob Hauser reg_qty = ci->volatile_reg_qty;
766dd9bd44fSJakob Hauser for (i = 0; i < reg_qty; i++) {
767dd9bd44fSJakob Hauser if (reg == ci->volatile_reg[i])
768dd9bd44fSJakob Hauser return true;
769dd9bd44fSJakob Hauser }
770dd9bd44fSJakob Hauser
771dd9bd44fSJakob Hauser return false;
772de8860b1SLinus Walleij }
773de8860b1SLinus Walleij
774de8860b1SLinus Walleij /* TODO: enable regmap cache, using mark dirty and sync at runtime resume */
775de8860b1SLinus Walleij static const struct regmap_config yas5xx_regmap_config = {
776de8860b1SLinus Walleij .reg_bits = 8,
777de8860b1SLinus Walleij .val_bits = 8,
778de8860b1SLinus Walleij .max_register = 0xff,
779de8860b1SLinus Walleij .volatile_reg = yas5xx_volatile_reg,
780de8860b1SLinus Walleij };
781de8860b1SLinus Walleij
782de8860b1SLinus Walleij /**
7836e3bfa97SJakob Hauser * yas530_extract_calibration() - extracts the a2-a9 and k calibration
784de8860b1SLinus Walleij * @data: the bitfield to use
785de8860b1SLinus Walleij * @c: the calibration to populate
7866e3bfa97SJakob Hauser *
7876e3bfa97SJakob Hauser * Used by YAS530, YAS532 and YAS533.
788de8860b1SLinus Walleij */
yas530_extract_calibration(u8 * data,struct yas5xx_calibration * c)7896e3bfa97SJakob Hauser static void yas530_extract_calibration(u8 *data, struct yas5xx_calibration *c)
790de8860b1SLinus Walleij {
791de8860b1SLinus Walleij u64 val = get_unaligned_be64(data);
792de8860b1SLinus Walleij
793de8860b1SLinus Walleij /*
794de8860b1SLinus Walleij * Bitfield layout for the axis calibration data, for factor
795de8860b1SLinus Walleij * a2 = 2 etc, k = k, c = clock divider
796de8860b1SLinus Walleij *
797de8860b1SLinus Walleij * n 7 6 5 4 3 2 1 0
798de8860b1SLinus Walleij * 0 [ 2 2 2 2 2 2 3 3 ] bits 63 .. 56
799de8860b1SLinus Walleij * 1 [ 3 3 4 4 4 4 4 4 ] bits 55 .. 48
800de8860b1SLinus Walleij * 2 [ 5 5 5 5 5 5 6 6 ] bits 47 .. 40
801de8860b1SLinus Walleij * 3 [ 6 6 6 6 7 7 7 7 ] bits 39 .. 32
802de8860b1SLinus Walleij * 4 [ 7 7 7 8 8 8 8 8 ] bits 31 .. 24
803de8860b1SLinus Walleij * 5 [ 8 9 9 9 9 9 9 9 ] bits 23 .. 16
804de8860b1SLinus Walleij * 6 [ 9 k k k k k c c ] bits 15 .. 8
805de8860b1SLinus Walleij * 7 [ c x x x x x x x ] bits 7 .. 0
806de8860b1SLinus Walleij */
807de8860b1SLinus Walleij c->a2 = FIELD_GET(GENMASK_ULL(63, 58), val) - 32;
808de8860b1SLinus Walleij c->a3 = FIELD_GET(GENMASK_ULL(57, 54), val) - 8;
809de8860b1SLinus Walleij c->a4 = FIELD_GET(GENMASK_ULL(53, 48), val) - 32;
810de8860b1SLinus Walleij c->a5 = FIELD_GET(GENMASK_ULL(47, 42), val) + 38;
811de8860b1SLinus Walleij c->a6 = FIELD_GET(GENMASK_ULL(41, 36), val) - 32;
812de8860b1SLinus Walleij c->a7 = FIELD_GET(GENMASK_ULL(35, 29), val) - 64;
813de8860b1SLinus Walleij c->a8 = FIELD_GET(GENMASK_ULL(28, 23), val) - 32;
814de8860b1SLinus Walleij c->a9 = FIELD_GET(GENMASK_ULL(22, 15), val);
815de8860b1SLinus Walleij c->k = FIELD_GET(GENMASK_ULL(14, 10), val) + 10;
816de8860b1SLinus Walleij c->dck = FIELD_GET(GENMASK_ULL(9, 7), val);
817de8860b1SLinus Walleij }
818de8860b1SLinus Walleij
yas530_get_calibration_data(struct yas5xx * yas5xx)819de8860b1SLinus Walleij static int yas530_get_calibration_data(struct yas5xx *yas5xx)
820de8860b1SLinus Walleij {
821de8860b1SLinus Walleij struct yas5xx_calibration *c = &yas5xx->calibration;
822de8860b1SLinus Walleij u8 data[16];
823de8860b1SLinus Walleij u32 val;
824de8860b1SLinus Walleij int ret;
825de8860b1SLinus Walleij
826de8860b1SLinus Walleij /* Dummy read, first read is ALWAYS wrong */
8276e3bfa97SJakob Hauser ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
828de8860b1SLinus Walleij if (ret)
829de8860b1SLinus Walleij return ret;
830de8860b1SLinus Walleij
831de8860b1SLinus Walleij /* Actual calibration readout */
8326e3bfa97SJakob Hauser ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
833de8860b1SLinus Walleij if (ret)
834de8860b1SLinus Walleij return ret;
835bdef8dcfSJakob Hauser dev_dbg(yas5xx->dev, "calibration data: %16ph\n", data);
836de8860b1SLinus Walleij
83792d9c05cSJakob Hauser /* Contribute calibration data to the input pool for kernel entropy */
838de8860b1SLinus Walleij add_device_randomness(data, sizeof(data));
83992d9c05cSJakob Hauser
84092d9c05cSJakob Hauser /* Extract version */
841de8860b1SLinus Walleij yas5xx->version = data[15] & GENMASK(1, 0);
842de8860b1SLinus Walleij
843de8860b1SLinus Walleij /* Extract the calibration from the bitfield */
844de8860b1SLinus Walleij c->Cx = data[0] * 6 - 768;
845de8860b1SLinus Walleij c->Cy1 = data[1] * 6 - 768;
846de8860b1SLinus Walleij c->Cy2 = data[2] * 6 - 768;
8476e3bfa97SJakob Hauser yas530_extract_calibration(&data[3], c);
848de8860b1SLinus Walleij
849de8860b1SLinus Walleij /*
850de8860b1SLinus Walleij * Extract linearization:
851de8860b1SLinus Walleij * Linearization layout in the 32 bits at byte 11:
852de8860b1SLinus Walleij * The r factors are 6 bit values where bit 5 is the sign
853de8860b1SLinus Walleij *
854de8860b1SLinus Walleij * n 7 6 5 4 3 2 1 0
855de8860b1SLinus Walleij * 0 [ xx xx xx r0 r0 r0 r0 r0 ] bits 31 .. 24
856de8860b1SLinus Walleij * 1 [ r0 f0 f0 r1 r1 r1 r1 r1 ] bits 23 .. 16
857de8860b1SLinus Walleij * 2 [ r1 f1 f1 r2 r2 r2 r2 r2 ] bits 15 .. 8
858de8860b1SLinus Walleij * 3 [ r2 f2 f2 xx xx xx xx xx ] bits 7 .. 0
859de8860b1SLinus Walleij */
860de8860b1SLinus Walleij val = get_unaligned_be32(&data[11]);
861de8860b1SLinus Walleij c->f[0] = FIELD_GET(GENMASK(22, 21), val);
862de8860b1SLinus Walleij c->f[1] = FIELD_GET(GENMASK(14, 13), val);
863de8860b1SLinus Walleij c->f[2] = FIELD_GET(GENMASK(6, 5), val);
864de8860b1SLinus Walleij c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5);
865de8860b1SLinus Walleij c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5);
866de8860b1SLinus Walleij c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5);
86792d9c05cSJakob Hauser
868de8860b1SLinus Walleij return 0;
869de8860b1SLinus Walleij }
870de8860b1SLinus Walleij
yas532_get_calibration_data(struct yas5xx * yas5xx)871de8860b1SLinus Walleij static int yas532_get_calibration_data(struct yas5xx *yas5xx)
872de8860b1SLinus Walleij {
873de8860b1SLinus Walleij struct yas5xx_calibration *c = &yas5xx->calibration;
874de8860b1SLinus Walleij u8 data[14];
875de8860b1SLinus Walleij u32 val;
876de8860b1SLinus Walleij int ret;
877de8860b1SLinus Walleij
878de8860b1SLinus Walleij /* Dummy read, first read is ALWAYS wrong */
8796e3bfa97SJakob Hauser ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
880de8860b1SLinus Walleij if (ret)
881de8860b1SLinus Walleij return ret;
882de8860b1SLinus Walleij /* Actual calibration readout */
8836e3bfa97SJakob Hauser ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
884de8860b1SLinus Walleij if (ret)
885de8860b1SLinus Walleij return ret;
886bdef8dcfSJakob Hauser dev_dbg(yas5xx->dev, "calibration data: %14ph\n", data);
887de8860b1SLinus Walleij
888de8860b1SLinus Walleij /* Sanity check, is this all zeroes? */
88992d9c05cSJakob Hauser if (!memchr_inv(data, 0x00, 13) && !(data[13] & BIT(7)))
890de8860b1SLinus Walleij dev_warn(yas5xx->dev, "calibration is blank!\n");
891de8860b1SLinus Walleij
89292d9c05cSJakob Hauser /* Contribute calibration data to the input pool for kernel entropy */
893de8860b1SLinus Walleij add_device_randomness(data, sizeof(data));
89492d9c05cSJakob Hauser
895de8860b1SLinus Walleij /* Only one bit of version info reserved here as far as we know */
896de8860b1SLinus Walleij yas5xx->version = data[13] & BIT(0);
897de8860b1SLinus Walleij
898de8860b1SLinus Walleij /* Extract calibration from the bitfield */
899de8860b1SLinus Walleij c->Cx = data[0] * 10 - 1280;
900de8860b1SLinus Walleij c->Cy1 = data[1] * 10 - 1280;
901de8860b1SLinus Walleij c->Cy2 = data[2] * 10 - 1280;
9026e3bfa97SJakob Hauser yas530_extract_calibration(&data[3], c);
90392d9c05cSJakob Hauser
904de8860b1SLinus Walleij /*
905de8860b1SLinus Walleij * Extract linearization:
906de8860b1SLinus Walleij * Linearization layout in the 32 bits at byte 10:
907de8860b1SLinus Walleij * The r factors are 6 bit values where bit 5 is the sign
908de8860b1SLinus Walleij *
909de8860b1SLinus Walleij * n 7 6 5 4 3 2 1 0
910de8860b1SLinus Walleij * 0 [ xx r0 r0 r0 r0 r0 r0 f0 ] bits 31 .. 24
911de8860b1SLinus Walleij * 1 [ f0 r1 r1 r1 r1 r1 r1 f1 ] bits 23 .. 16
912de8860b1SLinus Walleij * 2 [ f1 r2 r2 r2 r2 r2 r2 f2 ] bits 15 .. 8
913de8860b1SLinus Walleij * 3 [ f2 xx xx xx xx xx xx xx ] bits 7 .. 0
914de8860b1SLinus Walleij */
915de8860b1SLinus Walleij val = get_unaligned_be32(&data[10]);
916de8860b1SLinus Walleij c->f[0] = FIELD_GET(GENMASK(24, 23), val);
917de8860b1SLinus Walleij c->f[1] = FIELD_GET(GENMASK(16, 15), val);
918de8860b1SLinus Walleij c->f[2] = FIELD_GET(GENMASK(8, 7), val);
919de8860b1SLinus Walleij c->r[0] = sign_extend32(FIELD_GET(GENMASK(30, 25), val), 5);
920de8860b1SLinus Walleij c->r[1] = sign_extend32(FIELD_GET(GENMASK(22, 17), val), 5);
921de8860b1SLinus Walleij c->r[2] = sign_extend32(FIELD_GET(GENMASK(14, 7), val), 5);
922de8860b1SLinus Walleij
923de8860b1SLinus Walleij return 0;
924de8860b1SLinus Walleij }
925de8860b1SLinus Walleij
yas537_get_calibration_data(struct yas5xx * yas5xx)92665f79b50SJakob Hauser static int yas537_get_calibration_data(struct yas5xx *yas5xx)
92765f79b50SJakob Hauser {
92865f79b50SJakob Hauser struct yas5xx_calibration *c = &yas5xx->calibration;
92965f79b50SJakob Hauser u8 data[17];
93065f79b50SJakob Hauser u32 val1, val2, val3, val4;
93165f79b50SJakob Hauser int i, ret;
93265f79b50SJakob Hauser
93365f79b50SJakob Hauser /* Writing SRST register */
93465f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_SRST, BIT(1));
93565f79b50SJakob Hauser if (ret)
93665f79b50SJakob Hauser return ret;
93765f79b50SJakob Hauser
93865f79b50SJakob Hauser /* Calibration readout, YAS537 needs one readout only */
93965f79b50SJakob Hauser ret = regmap_bulk_read(yas5xx->map, YAS537_CAL, data, sizeof(data));
94065f79b50SJakob Hauser if (ret)
94165f79b50SJakob Hauser return ret;
94265f79b50SJakob Hauser dev_dbg(yas5xx->dev, "calibration data: %17ph\n", data);
94365f79b50SJakob Hauser
94465f79b50SJakob Hauser /* Sanity check, is this all zeroes? */
94565f79b50SJakob Hauser if (!memchr_inv(data, 0x00, 16) && !FIELD_GET(GENMASK(5, 0), data[16]))
94665f79b50SJakob Hauser dev_warn(yas5xx->dev, "calibration is blank!\n");
94765f79b50SJakob Hauser
94865f79b50SJakob Hauser /* Contribute calibration data to the input pool for kernel entropy */
94965f79b50SJakob Hauser add_device_randomness(data, sizeof(data));
95065f79b50SJakob Hauser
95165f79b50SJakob Hauser /* Extract version information */
95265f79b50SJakob Hauser yas5xx->version = FIELD_GET(GENMASK(7, 6), data[16]);
95365f79b50SJakob Hauser
95465f79b50SJakob Hauser /* There are two versions of YAS537 behaving differently */
95565f79b50SJakob Hauser switch (yas5xx->version) {
95665f79b50SJakob Hauser case YAS537_VERSION_0:
95765f79b50SJakob Hauser /*
95865f79b50SJakob Hauser * The first version simply writes data back into registers:
95965f79b50SJakob Hauser *
96065f79b50SJakob Hauser * data[0] YAS537_MTC 0x93
96165f79b50SJakob Hauser * data[1] 0x94
96265f79b50SJakob Hauser * data[2] 0x95
96365f79b50SJakob Hauser * data[3] 0x96
96465f79b50SJakob Hauser * data[4] 0x97
96565f79b50SJakob Hauser * data[5] 0x98
96665f79b50SJakob Hauser * data[6] 0x99
96765f79b50SJakob Hauser * data[7] 0x9a
96865f79b50SJakob Hauser * data[8] 0x9b
96965f79b50SJakob Hauser * data[9] 0x9c
97065f79b50SJakob Hauser * data[10] 0x9d
97165f79b50SJakob Hauser * data[11] YAS537_OC 0x9e
97265f79b50SJakob Hauser *
97365f79b50SJakob Hauser * data[12] YAS537_OFFSET_X 0x84
97465f79b50SJakob Hauser * data[13] YAS537_OFFSET_Y1 0x85
97565f79b50SJakob Hauser * data[14] YAS537_OFFSET_Y2 0x86
97665f79b50SJakob Hauser *
97765f79b50SJakob Hauser * data[15] YAS537_HCK 0x88
97865f79b50SJakob Hauser * data[16] YAS537_LCK 0x89
97965f79b50SJakob Hauser */
98065f79b50SJakob Hauser for (i = 0; i < 12; i++) {
98165f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_MTC + i,
98265f79b50SJakob Hauser data[i]);
98365f79b50SJakob Hauser if (ret)
98465f79b50SJakob Hauser return ret;
98565f79b50SJakob Hauser }
98665f79b50SJakob Hauser for (i = 0; i < 3; i++) {
98765f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_OFFSET_X + i,
98865f79b50SJakob Hauser data[i + 12]);
98965f79b50SJakob Hauser if (ret)
99065f79b50SJakob Hauser return ret;
99165f79b50SJakob Hauser yas5xx->hard_offsets[i] = data[i + 12];
99265f79b50SJakob Hauser }
99365f79b50SJakob Hauser for (i = 0; i < 2; i++) {
99465f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_HCK + i,
99565f79b50SJakob Hauser data[i + 15]);
99665f79b50SJakob Hauser if (ret)
99765f79b50SJakob Hauser return ret;
99865f79b50SJakob Hauser }
99965f79b50SJakob Hauser break;
100065f79b50SJakob Hauser case YAS537_VERSION_1:
100165f79b50SJakob Hauser /*
100265f79b50SJakob Hauser * The second version writes some data into registers but also
100365f79b50SJakob Hauser * extracts calibration coefficients.
100465f79b50SJakob Hauser *
100565f79b50SJakob Hauser * Registers being written:
100665f79b50SJakob Hauser *
100765f79b50SJakob Hauser * data[0] YAS537_MTC 0x93
100865f79b50SJakob Hauser * data[1] YAS537_MTC+1 0x94
100965f79b50SJakob Hauser * data[2] YAS537_MTC+2 0x95
101065f79b50SJakob Hauser * data[3] YAS537_MTC+3 (partially) 0x96
101165f79b50SJakob Hauser *
101265f79b50SJakob Hauser * data[12] YAS537_OFFSET_X 0x84
101365f79b50SJakob Hauser * data[13] YAS537_OFFSET_Y1 0x85
101465f79b50SJakob Hauser * data[14] YAS537_OFFSET_Y2 0x86
101565f79b50SJakob Hauser *
101665f79b50SJakob Hauser * data[15] YAS537_HCK (partially) 0x88
101765f79b50SJakob Hauser * YAS537_LCK (partially) 0x89
101865f79b50SJakob Hauser * data[16] YAS537_OC (partially) 0x9e
101965f79b50SJakob Hauser */
102065f79b50SJakob Hauser for (i = 0; i < 3; i++) {
102165f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_MTC + i,
102265f79b50SJakob Hauser data[i]);
102365f79b50SJakob Hauser if (ret)
102465f79b50SJakob Hauser return ret;
102565f79b50SJakob Hauser }
102665f79b50SJakob Hauser for (i = 0; i < 3; i++) {
102765f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_OFFSET_X + i,
102865f79b50SJakob Hauser data[i + 12]);
102965f79b50SJakob Hauser if (ret)
103065f79b50SJakob Hauser return ret;
103165f79b50SJakob Hauser yas5xx->hard_offsets[i] = data[i + 12];
103265f79b50SJakob Hauser }
103365f79b50SJakob Hauser /*
103465f79b50SJakob Hauser * Visualization of partially taken data:
103565f79b50SJakob Hauser *
103665f79b50SJakob Hauser * data[3] n 7 6 5 4 3 2 1 0
103765f79b50SJakob Hauser * YAS537_MTC+3 x x x 1 0 0 0 0
103865f79b50SJakob Hauser *
103965f79b50SJakob Hauser * data[15] n 7 6 5 4 3 2 1 0
104065f79b50SJakob Hauser * YAS537_HCK x x x x 0
104165f79b50SJakob Hauser *
104265f79b50SJakob Hauser * data[15] n 7 6 5 4 3 2 1 0
104365f79b50SJakob Hauser * YAS537_LCK x x x x 0
104465f79b50SJakob Hauser *
104565f79b50SJakob Hauser * data[16] n 7 6 5 4 3 2 1 0
104665f79b50SJakob Hauser * YAS537_OC x x x x x x
104765f79b50SJakob Hauser */
104865f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_MTC + 3,
104965f79b50SJakob Hauser FIELD_PREP(YAS537_MTC3_MASK_PREP,
105065f79b50SJakob Hauser FIELD_GET(YAS537_MTC3_MASK_GET, data[3])) |
105165f79b50SJakob Hauser YAS537_MTC3_ADD_BIT);
105265f79b50SJakob Hauser if (ret)
105365f79b50SJakob Hauser return ret;
105465f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_HCK,
105565f79b50SJakob Hauser FIELD_PREP(YAS537_HCK_MASK_PREP,
105665f79b50SJakob Hauser FIELD_GET(YAS537_HCK_MASK_GET, data[15])));
105765f79b50SJakob Hauser if (ret)
105865f79b50SJakob Hauser return ret;
105965f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_LCK,
106065f79b50SJakob Hauser FIELD_PREP(YAS537_LCK_MASK_PREP,
106165f79b50SJakob Hauser FIELD_GET(YAS537_LCK_MASK_GET, data[15])));
106265f79b50SJakob Hauser if (ret)
106365f79b50SJakob Hauser return ret;
106465f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_OC,
106565f79b50SJakob Hauser FIELD_GET(YAS537_OC_MASK_GET, data[16]));
106665f79b50SJakob Hauser if (ret)
106765f79b50SJakob Hauser return ret;
106865f79b50SJakob Hauser /*
106965f79b50SJakob Hauser * For data extraction, build some blocks. Four 32-bit blocks
107065f79b50SJakob Hauser * look appropriate.
107165f79b50SJakob Hauser *
107265f79b50SJakob Hauser * n 7 6 5 4 3 2 1 0
107365f79b50SJakob Hauser * data[0] 0 [ Cx Cx Cx Cx Cx Cx Cx Cx ] bits 31 .. 24
107465f79b50SJakob Hauser * data[1] 1 [ Cx C1 C1 C1 C1 C1 C1 C1 ] bits 23 .. 16
107565f79b50SJakob Hauser * data[2] 2 [ C1 C1 C2 C2 C2 C2 C2 C2 ] bits 15 .. 8
107665f79b50SJakob Hauser * data[3] 3 [ C2 C2 C2 ] bits 7 .. 0
107765f79b50SJakob Hauser *
107865f79b50SJakob Hauser * n 7 6 5 4 3 2 1 0
107965f79b50SJakob Hauser * data[3] 0 [ a2 a2 a2 a2 a2 ] bits 31 .. 24
108065f79b50SJakob Hauser * data[4] 1 [ a2 a2 a3 a3 a3 a3 a3 a3 ] bits 23 .. 16
108165f79b50SJakob Hauser * data[5] 2 [ a3 a4 a4 a4 a4 a4 a4 a4 ] bits 15 .. 8
108265f79b50SJakob Hauser * data[6] 3 [ a4 ] bits 7 .. 0
108365f79b50SJakob Hauser *
108465f79b50SJakob Hauser * n 7 6 5 4 3 2 1 0
108565f79b50SJakob Hauser * data[6] 0 [ a5 a5 a5 a5 a5 a5 a5 ] bits 31 .. 24
108665f79b50SJakob Hauser * data[7] 1 [ a5 a5 a6 a6 a6 a6 a6 a6 ] bits 23 .. 16
108765f79b50SJakob Hauser * data[8] 2 [ a6 a7 a7 a7 a7 a7 a7 a7 ] bits 15 .. 8
108865f79b50SJakob Hauser * data[9] 3 [ a7 ] bits 7 .. 0
108965f79b50SJakob Hauser *
109065f79b50SJakob Hauser * n 7 6 5 4 3 2 1 0
109165f79b50SJakob Hauser * data[9] 0 [ a8 a8 a8 a8 a8 a8 a8 ] bits 31 .. 24
109265f79b50SJakob Hauser * data[10] 1 [ a9 a9 a9 a9 a9 a9 a9 a9 ] bits 23 .. 16
109365f79b50SJakob Hauser * data[11] 2 [ a9 k k k k k k k ] bits 15 .. 8
109465f79b50SJakob Hauser * data[12] 3 [ ] bits 7 .. 0
109565f79b50SJakob Hauser */
109665f79b50SJakob Hauser val1 = get_unaligned_be32(&data[0]);
109765f79b50SJakob Hauser val2 = get_unaligned_be32(&data[3]);
109865f79b50SJakob Hauser val3 = get_unaligned_be32(&data[6]);
109965f79b50SJakob Hauser val4 = get_unaligned_be32(&data[9]);
110065f79b50SJakob Hauser /* Extract calibration coefficients and modify */
110165f79b50SJakob Hauser c->Cx = FIELD_GET(GENMASK(31, 23), val1) - 256;
110265f79b50SJakob Hauser c->Cy1 = FIELD_GET(GENMASK(22, 14), val1) - 256;
110365f79b50SJakob Hauser c->Cy2 = FIELD_GET(GENMASK(13, 5), val1) - 256;
110465f79b50SJakob Hauser c->a2 = FIELD_GET(GENMASK(28, 22), val2) - 64;
110565f79b50SJakob Hauser c->a3 = FIELD_GET(GENMASK(21, 15), val2) - 64;
110665f79b50SJakob Hauser c->a4 = FIELD_GET(GENMASK(14, 7), val2) - 128;
110765f79b50SJakob Hauser c->a5 = FIELD_GET(GENMASK(30, 22), val3) - 112;
110865f79b50SJakob Hauser c->a6 = FIELD_GET(GENMASK(21, 15), val3) - 64;
110965f79b50SJakob Hauser c->a7 = FIELD_GET(GENMASK(14, 7), val3) - 128;
111065f79b50SJakob Hauser c->a8 = FIELD_GET(GENMASK(30, 24), val4) - 64;
111165f79b50SJakob Hauser c->a9 = FIELD_GET(GENMASK(23, 15), val4) - 112;
111265f79b50SJakob Hauser c->k = FIELD_GET(GENMASK(14, 8), val4);
111365f79b50SJakob Hauser break;
111465f79b50SJakob Hauser default:
111565f79b50SJakob Hauser dev_err(yas5xx->dev, "unknown version of YAS537\n");
111665f79b50SJakob Hauser return -EINVAL;
111765f79b50SJakob Hauser }
111865f79b50SJakob Hauser
111965f79b50SJakob Hauser return 0;
112065f79b50SJakob Hauser }
112165f79b50SJakob Hauser
11226e3bfa97SJakob Hauser /* Used by YAS530, YAS532 and YAS533 */
yas530_dump_calibration(struct yas5xx * yas5xx)11236e3bfa97SJakob Hauser static void yas530_dump_calibration(struct yas5xx *yas5xx)
1124de8860b1SLinus Walleij {
1125de8860b1SLinus Walleij struct yas5xx_calibration *c = &yas5xx->calibration;
1126de8860b1SLinus Walleij
1127de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "f[] = [%d, %d, %d]\n",
1128de8860b1SLinus Walleij c->f[0], c->f[1], c->f[2]);
1129de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "r[] = [%d, %d, %d]\n",
1130de8860b1SLinus Walleij c->r[0], c->r[1], c->r[2]);
1131de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "Cx = %d\n", c->Cx);
1132de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "Cy1 = %d\n", c->Cy1);
1133de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "Cy2 = %d\n", c->Cy2);
1134de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "a2 = %d\n", c->a2);
1135de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "a3 = %d\n", c->a3);
1136de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "a4 = %d\n", c->a4);
1137de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "a5 = %d\n", c->a5);
1138de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "a6 = %d\n", c->a6);
1139de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "a7 = %d\n", c->a7);
1140de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "a8 = %d\n", c->a8);
1141de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "a9 = %d\n", c->a9);
1142de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "k = %d\n", c->k);
1143de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "dck = %d\n", c->dck);
1144de8860b1SLinus Walleij }
1145de8860b1SLinus Walleij
yas537_dump_calibration(struct yas5xx * yas5xx)114665f79b50SJakob Hauser static void yas537_dump_calibration(struct yas5xx *yas5xx)
114765f79b50SJakob Hauser {
114865f79b50SJakob Hauser struct yas5xx_calibration *c = &yas5xx->calibration;
114965f79b50SJakob Hauser
115065f79b50SJakob Hauser if (yas5xx->version == YAS537_VERSION_1) {
115165f79b50SJakob Hauser dev_dbg(yas5xx->dev, "Cx = %d\n", c->Cx);
115265f79b50SJakob Hauser dev_dbg(yas5xx->dev, "Cy1 = %d\n", c->Cy1);
115365f79b50SJakob Hauser dev_dbg(yas5xx->dev, "Cy2 = %d\n", c->Cy2);
115465f79b50SJakob Hauser dev_dbg(yas5xx->dev, "a2 = %d\n", c->a2);
115565f79b50SJakob Hauser dev_dbg(yas5xx->dev, "a3 = %d\n", c->a3);
115665f79b50SJakob Hauser dev_dbg(yas5xx->dev, "a4 = %d\n", c->a4);
115765f79b50SJakob Hauser dev_dbg(yas5xx->dev, "a5 = %d\n", c->a5);
115865f79b50SJakob Hauser dev_dbg(yas5xx->dev, "a6 = %d\n", c->a6);
115965f79b50SJakob Hauser dev_dbg(yas5xx->dev, "a7 = %d\n", c->a7);
116065f79b50SJakob Hauser dev_dbg(yas5xx->dev, "a8 = %d\n", c->a8);
116165f79b50SJakob Hauser dev_dbg(yas5xx->dev, "a9 = %d\n", c->a9);
116265f79b50SJakob Hauser dev_dbg(yas5xx->dev, "k = %d\n", c->k);
116365f79b50SJakob Hauser }
116465f79b50SJakob Hauser }
116565f79b50SJakob Hauser
11666e3bfa97SJakob Hauser /* Used by YAS530, YAS532 and YAS533 */
yas530_set_offsets(struct yas5xx * yas5xx,s8 ox,s8 oy1,s8 oy2)11676e3bfa97SJakob Hauser static int yas530_set_offsets(struct yas5xx *yas5xx, s8 ox, s8 oy1, s8 oy2)
1168de8860b1SLinus Walleij {
1169de8860b1SLinus Walleij int ret;
1170de8860b1SLinus Walleij
11716e3bfa97SJakob Hauser ret = regmap_write(yas5xx->map, YAS530_OFFSET_X, ox);
1172de8860b1SLinus Walleij if (ret)
1173de8860b1SLinus Walleij return ret;
11746e3bfa97SJakob Hauser ret = regmap_write(yas5xx->map, YAS530_OFFSET_Y1, oy1);
1175de8860b1SLinus Walleij if (ret)
1176de8860b1SLinus Walleij return ret;
11776e3bfa97SJakob Hauser return regmap_write(yas5xx->map, YAS530_OFFSET_Y2, oy2);
1178de8860b1SLinus Walleij }
1179de8860b1SLinus Walleij
11806e3bfa97SJakob Hauser /* Used by YAS530, YAS532 and YAS533 */
yas530_adjust_offset(s8 old,int bit,u16 center,u16 measure)11816e3bfa97SJakob Hauser static s8 yas530_adjust_offset(s8 old, int bit, u16 center, u16 measure)
1182de8860b1SLinus Walleij {
1183de8860b1SLinus Walleij if (measure > center)
1184de8860b1SLinus Walleij return old + BIT(bit);
1185de8860b1SLinus Walleij if (measure < center)
1186de8860b1SLinus Walleij return old - BIT(bit);
1187de8860b1SLinus Walleij return old;
1188de8860b1SLinus Walleij }
1189de8860b1SLinus Walleij
11906e3bfa97SJakob Hauser /* Used by YAS530, YAS532 and YAS533 */
yas530_measure_offsets(struct yas5xx * yas5xx)11916e3bfa97SJakob Hauser static int yas530_measure_offsets(struct yas5xx *yas5xx)
1192de8860b1SLinus Walleij {
1193a70f60e5SJakob Hauser const struct yas5xx_chip_info *ci = yas5xx->chip_info;
1194de8860b1SLinus Walleij int ret;
1195de8860b1SLinus Walleij u16 center;
1196de8860b1SLinus Walleij u16 t, x, y1, y2;
1197de8860b1SLinus Walleij s8 ox, oy1, oy2;
1198de8860b1SLinus Walleij int i;
1199de8860b1SLinus Walleij
1200de8860b1SLinus Walleij /* Actuate the init coil and measure offsets */
12016e3bfa97SJakob Hauser ret = regmap_write(yas5xx->map, YAS530_ACTUATE_INIT_COIL, 0);
1202de8860b1SLinus Walleij if (ret)
1203de8860b1SLinus Walleij return ret;
1204de8860b1SLinus Walleij
1205de8860b1SLinus Walleij /* When the initcoil is active this should be around the center */
1206a70f60e5SJakob Hauser switch (ci->devid) {
1207de8860b1SLinus Walleij case YAS530_DEVICE_ID:
1208de8860b1SLinus Walleij center = YAS530_DATA_CENTER;
1209de8860b1SLinus Walleij break;
1210de8860b1SLinus Walleij case YAS532_DEVICE_ID:
1211de8860b1SLinus Walleij center = YAS532_DATA_CENTER;
1212de8860b1SLinus Walleij break;
1213de8860b1SLinus Walleij default:
1214de8860b1SLinus Walleij dev_err(yas5xx->dev, "unknown device type\n");
1215de8860b1SLinus Walleij return -EINVAL;
1216de8860b1SLinus Walleij }
1217de8860b1SLinus Walleij
1218de8860b1SLinus Walleij /*
1219de8860b1SLinus Walleij * We set offsets in the interval +-31 by iterating
1220de8860b1SLinus Walleij * +-16, +-8, +-4, +-2, +-1 adjusting the offsets each
1221de8860b1SLinus Walleij * time, then writing the final offsets into the
1222de8860b1SLinus Walleij * registers.
1223de8860b1SLinus Walleij *
1224de8860b1SLinus Walleij * NOTE: these offsets are NOT in the same unit or magnitude
1225de8860b1SLinus Walleij * as the values for [x, y1, y2]. The value is +/-31
1226de8860b1SLinus Walleij * but the effect on the raw values is much larger.
1227de8860b1SLinus Walleij * The effect of the offset is to bring the measure
1228de8860b1SLinus Walleij * rougly to the center.
1229de8860b1SLinus Walleij */
1230de8860b1SLinus Walleij ox = 0;
1231de8860b1SLinus Walleij oy1 = 0;
1232de8860b1SLinus Walleij oy2 = 0;
1233de8860b1SLinus Walleij
1234de8860b1SLinus Walleij for (i = 4; i >= 0; i--) {
12356e3bfa97SJakob Hauser ret = yas530_set_offsets(yas5xx, ox, oy1, oy2);
1236de8860b1SLinus Walleij if (ret)
1237de8860b1SLinus Walleij return ret;
1238de8860b1SLinus Walleij
12396e3bfa97SJakob Hauser ret = yas530_measure(yas5xx, &t, &x, &y1, &y2);
1240de8860b1SLinus Walleij if (ret)
1241de8860b1SLinus Walleij return ret;
1242de8860b1SLinus Walleij dev_dbg(yas5xx->dev, "measurement %d: x=%d, y1=%d, y2=%d\n",
1243de8860b1SLinus Walleij 5-i, x, y1, y2);
1244de8860b1SLinus Walleij
12456e3bfa97SJakob Hauser ox = yas530_adjust_offset(ox, i, center, x);
12466e3bfa97SJakob Hauser oy1 = yas530_adjust_offset(oy1, i, center, y1);
12476e3bfa97SJakob Hauser oy2 = yas530_adjust_offset(oy2, i, center, y2);
1248de8860b1SLinus Walleij }
1249de8860b1SLinus Walleij
1250de8860b1SLinus Walleij /* Needed for calibration algorithm */
1251de8860b1SLinus Walleij yas5xx->hard_offsets[0] = ox;
1252de8860b1SLinus Walleij yas5xx->hard_offsets[1] = oy1;
1253de8860b1SLinus Walleij yas5xx->hard_offsets[2] = oy2;
12546e3bfa97SJakob Hauser ret = yas530_set_offsets(yas5xx, ox, oy1, oy2);
1255de8860b1SLinus Walleij if (ret)
1256de8860b1SLinus Walleij return ret;
1257de8860b1SLinus Walleij
1258de8860b1SLinus Walleij dev_info(yas5xx->dev, "discovered hard offsets: x=%d, y1=%d, y2=%d\n",
1259de8860b1SLinus Walleij ox, oy1, oy2);
1260de8860b1SLinus Walleij return 0;
1261de8860b1SLinus Walleij }
1262de8860b1SLinus Walleij
12636e3bfa97SJakob Hauser /* Used by YAS530, YAS532 and YAS533 */
yas530_power_on(struct yas5xx * yas5xx)12646e3bfa97SJakob Hauser static int yas530_power_on(struct yas5xx *yas5xx)
1265de8860b1SLinus Walleij {
1266de8860b1SLinus Walleij unsigned int val;
1267de8860b1SLinus Walleij int ret;
1268de8860b1SLinus Walleij
1269de8860b1SLinus Walleij /* Zero the test registers */
12706e3bfa97SJakob Hauser ret = regmap_write(yas5xx->map, YAS530_TEST1, 0);
1271de8860b1SLinus Walleij if (ret)
1272de8860b1SLinus Walleij return ret;
12736e3bfa97SJakob Hauser ret = regmap_write(yas5xx->map, YAS530_TEST2, 0);
1274de8860b1SLinus Walleij if (ret)
1275de8860b1SLinus Walleij return ret;
1276de8860b1SLinus Walleij
1277de8860b1SLinus Walleij /* Set up for no interrupts, calibrated clock divider */
1278de8860b1SLinus Walleij val = FIELD_PREP(YAS5XX_CONFIG_CCK_MASK, yas5xx->calibration.dck);
12796e3bfa97SJakob Hauser ret = regmap_write(yas5xx->map, YAS530_CONFIG, val);
1280de8860b1SLinus Walleij if (ret)
1281de8860b1SLinus Walleij return ret;
1282de8860b1SLinus Walleij
1283de8860b1SLinus Walleij /* Measure interval 0 (back-to-back?) */
12846e3bfa97SJakob Hauser return regmap_write(yas5xx->map, YAS530_MEASURE_INTERVAL, 0);
1285de8860b1SLinus Walleij }
1286de8860b1SLinus Walleij
yas537_power_on(struct yas5xx * yas5xx)128765f79b50SJakob Hauser static int yas537_power_on(struct yas5xx *yas5xx)
128865f79b50SJakob Hauser {
128965f79b50SJakob Hauser __be16 buf;
129065f79b50SJakob Hauser int ret;
129165f79b50SJakob Hauser u8 intrvl;
129265f79b50SJakob Hauser
129365f79b50SJakob Hauser /* Writing ADCCAL and TRM registers */
129465f79b50SJakob Hauser buf = cpu_to_be16(GENMASK(9, 3));
129565f79b50SJakob Hauser ret = regmap_bulk_write(yas5xx->map, YAS537_ADCCAL, &buf, sizeof(buf));
129665f79b50SJakob Hauser if (ret)
129765f79b50SJakob Hauser return ret;
129865f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_TRM, GENMASK(7, 0));
129965f79b50SJakob Hauser if (ret)
130065f79b50SJakob Hauser return ret;
130165f79b50SJakob Hauser
130265f79b50SJakob Hauser /* The interval value is static in regular operation */
130365f79b50SJakob Hauser intrvl = (YAS537_DEFAULT_SENSOR_DELAY_MS * MILLI
130465f79b50SJakob Hauser - YAS537_MEASURE_TIME_WORST_US) / 4100;
130565f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_MEASURE_INTERVAL, intrvl);
130665f79b50SJakob Hauser if (ret)
130765f79b50SJakob Hauser return ret;
130865f79b50SJakob Hauser
130965f79b50SJakob Hauser /* The average value is also static in regular operation */
131065f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_AVR, YAS537_MAG_AVERAGE_32_MASK);
131165f79b50SJakob Hauser if (ret)
131265f79b50SJakob Hauser return ret;
131365f79b50SJakob Hauser
131465f79b50SJakob Hauser /* Perform the "rcoil" part but skip the "last_after_rcoil" read */
131565f79b50SJakob Hauser ret = regmap_write(yas5xx->map, YAS537_CONFIG, BIT(3));
131665f79b50SJakob Hauser if (ret)
131765f79b50SJakob Hauser return ret;
131865f79b50SJakob Hauser
131965f79b50SJakob Hauser /* Wait until the coil has ramped up */
132065f79b50SJakob Hauser usleep_range(YAS537_MAG_RCOIL_TIME_US, YAS537_MAG_RCOIL_TIME_US + 100);
132165f79b50SJakob Hauser
132265f79b50SJakob Hauser return 0;
132365f79b50SJakob Hauser }
132465f79b50SJakob Hauser
1325a70f60e5SJakob Hauser static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
1326a70f60e5SJakob Hauser [yas530] = {
1327a70f60e5SJakob Hauser .devid = YAS530_DEVICE_ID,
1328a70f60e5SJakob Hauser .product_name = "YAS530 MS-3E",
1329a70f60e5SJakob Hauser .version_names = { "A", "B" },
1330dd9bd44fSJakob Hauser .volatile_reg = yas530_volatile_reg,
1331dd9bd44fSJakob Hauser .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
1332913fd409SJakob Hauser .scaling_val2 = 100000000, /* picotesla to Gauss */
13332d6676ecSJakob Hauser .t_ref = 182, /* counts */
13342d6676ecSJakob Hauser .min_temp_x10 = -620, /* 1/10:s degrees Celsius */
1335059ff0f9SJakob Hauser .get_measure = yas530_get_measure,
1336059ff0f9SJakob Hauser .get_calibration_data = yas530_get_calibration_data,
1337059ff0f9SJakob Hauser .dump_calibration = yas530_dump_calibration,
1338059ff0f9SJakob Hauser .measure_offsets = yas530_measure_offsets,
1339059ff0f9SJakob Hauser .power_on = yas530_power_on,
1340a70f60e5SJakob Hauser },
1341a70f60e5SJakob Hauser [yas532] = {
1342a70f60e5SJakob Hauser .devid = YAS532_DEVICE_ID,
1343a70f60e5SJakob Hauser .product_name = "YAS532 MS-3R",
1344a70f60e5SJakob Hauser .version_names = { "AB", "AC" },
1345dd9bd44fSJakob Hauser .volatile_reg = yas530_volatile_reg,
1346dd9bd44fSJakob Hauser .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
1347913fd409SJakob Hauser .scaling_val2 = 100000, /* nanotesla to Gauss */
13482d6676ecSJakob Hauser .t_ref = 390, /* counts */
13492d6676ecSJakob Hauser .min_temp_x10 = -500, /* 1/10:s degrees Celsius */
1350059ff0f9SJakob Hauser .get_measure = yas530_get_measure,
1351059ff0f9SJakob Hauser .get_calibration_data = yas532_get_calibration_data,
1352059ff0f9SJakob Hauser .dump_calibration = yas530_dump_calibration,
1353059ff0f9SJakob Hauser .measure_offsets = yas530_measure_offsets,
1354059ff0f9SJakob Hauser .power_on = yas530_power_on,
1355a70f60e5SJakob Hauser },
1356a70f60e5SJakob Hauser [yas533] = {
1357a70f60e5SJakob Hauser .devid = YAS532_DEVICE_ID,
1358a70f60e5SJakob Hauser .product_name = "YAS533 MS-3F",
1359a70f60e5SJakob Hauser .version_names = { "AB", "AC" },
1360dd9bd44fSJakob Hauser .volatile_reg = yas530_volatile_reg,
1361dd9bd44fSJakob Hauser .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
1362913fd409SJakob Hauser .scaling_val2 = 100000, /* nanotesla to Gauss */
13632d6676ecSJakob Hauser .t_ref = 390, /* counts */
13642d6676ecSJakob Hauser .min_temp_x10 = -500, /* 1/10:s degrees Celsius */
1365059ff0f9SJakob Hauser .get_measure = yas530_get_measure,
1366059ff0f9SJakob Hauser .get_calibration_data = yas532_get_calibration_data,
1367059ff0f9SJakob Hauser .dump_calibration = yas530_dump_calibration,
1368059ff0f9SJakob Hauser .measure_offsets = yas530_measure_offsets,
1369059ff0f9SJakob Hauser .power_on = yas530_power_on,
1370a70f60e5SJakob Hauser },
137165f79b50SJakob Hauser [yas537] = {
137265f79b50SJakob Hauser .devid = YAS537_DEVICE_ID,
137365f79b50SJakob Hauser .product_name = "YAS537 MS-3T",
137465f79b50SJakob Hauser .version_names = { "v0", "v1" }, /* version naming unknown */
137565f79b50SJakob Hauser .volatile_reg = yas537_volatile_reg,
137665f79b50SJakob Hauser .volatile_reg_qty = ARRAY_SIZE(yas537_volatile_reg),
137765f79b50SJakob Hauser .scaling_val2 = 100000, /* nanotesla to Gauss */
137865f79b50SJakob Hauser .t_ref = 8120, /* counts */
137965f79b50SJakob Hauser .min_temp_x10 = -3860, /* 1/10:s degrees Celsius */
138065f79b50SJakob Hauser .get_measure = yas537_get_measure,
138165f79b50SJakob Hauser .get_calibration_data = yas537_get_calibration_data,
138265f79b50SJakob Hauser .dump_calibration = yas537_dump_calibration,
138365f79b50SJakob Hauser /* .measure_offets is not needed for yas537 */
138465f79b50SJakob Hauser .power_on = yas537_power_on,
138565f79b50SJakob Hauser },
1386a70f60e5SJakob Hauser };
1387a70f60e5SJakob Hauser
yas5xx_probe(struct i2c_client * i2c)1388fcd96967SUwe Kleine-König static int yas5xx_probe(struct i2c_client *i2c)
1389de8860b1SLinus Walleij {
1390fcd96967SUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
1391de8860b1SLinus Walleij struct iio_dev *indio_dev;
1392de8860b1SLinus Walleij struct device *dev = &i2c->dev;
1393de8860b1SLinus Walleij struct yas5xx *yas5xx;
1394a70f60e5SJakob Hauser const struct yas5xx_chip_info *ci;
1395a70f60e5SJakob Hauser int id_check;
1396de8860b1SLinus Walleij int ret;
1397de8860b1SLinus Walleij
1398de8860b1SLinus Walleij indio_dev = devm_iio_device_alloc(dev, sizeof(*yas5xx));
1399de8860b1SLinus Walleij if (!indio_dev)
1400de8860b1SLinus Walleij return -ENOMEM;
1401de8860b1SLinus Walleij
1402de8860b1SLinus Walleij yas5xx = iio_priv(indio_dev);
1403de8860b1SLinus Walleij i2c_set_clientdata(i2c, indio_dev);
1404de8860b1SLinus Walleij yas5xx->dev = dev;
1405de8860b1SLinus Walleij mutex_init(&yas5xx->lock);
1406de8860b1SLinus Walleij
1407b892770aSAndy Shevchenko ret = iio_read_mount_matrix(dev, &yas5xx->orientation);
1408de8860b1SLinus Walleij if (ret)
1409de8860b1SLinus Walleij return ret;
1410de8860b1SLinus Walleij
1411de8860b1SLinus Walleij yas5xx->regs[0].supply = "vdd";
1412de8860b1SLinus Walleij yas5xx->regs[1].supply = "iovdd";
1413de8860b1SLinus Walleij ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(yas5xx->regs),
1414de8860b1SLinus Walleij yas5xx->regs);
1415de8860b1SLinus Walleij if (ret)
1416de8860b1SLinus Walleij return dev_err_probe(dev, ret, "cannot get regulators\n");
1417de8860b1SLinus Walleij
1418de8860b1SLinus Walleij ret = regulator_bulk_enable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
1419d05d7377SAndy Shevchenko if (ret)
1420d05d7377SAndy Shevchenko return dev_err_probe(dev, ret, "cannot enable regulators\n");
1421de8860b1SLinus Walleij
1422de8860b1SLinus Walleij /* See comment in runtime resume callback */
1423de8860b1SLinus Walleij usleep_range(31000, 40000);
1424de8860b1SLinus Walleij
1425de8860b1SLinus Walleij /* This will take the device out of reset if need be */
1426de8860b1SLinus Walleij yas5xx->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
1427de8860b1SLinus Walleij if (IS_ERR(yas5xx->reset)) {
1428d05d7377SAndy Shevchenko ret = dev_err_probe(dev, PTR_ERR(yas5xx->reset), "failed to get reset line\n");
1429de8860b1SLinus Walleij goto reg_off;
1430de8860b1SLinus Walleij }
1431de8860b1SLinus Walleij
1432de8860b1SLinus Walleij yas5xx->map = devm_regmap_init_i2c(i2c, &yas5xx_regmap_config);
1433de8860b1SLinus Walleij if (IS_ERR(yas5xx->map)) {
1434d05d7377SAndy Shevchenko ret = dev_err_probe(dev, PTR_ERR(yas5xx->map), "failed to allocate register map\n");
1435de8860b1SLinus Walleij goto assert_reset;
1436de8860b1SLinus Walleij }
1437de8860b1SLinus Walleij
1438741d1e37SAndy Shevchenko ci = device_get_match_data(dev);
1439741d1e37SAndy Shevchenko if (!ci)
1440741d1e37SAndy Shevchenko ci = (const struct yas5xx_chip_info *)id->driver_data;
1441741d1e37SAndy Shevchenko yas5xx->chip_info = ci;
1442a70f60e5SJakob Hauser
1443a70f60e5SJakob Hauser ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check);
1444de8860b1SLinus Walleij if (ret)
1445de8860b1SLinus Walleij goto assert_reset;
1446de8860b1SLinus Walleij
1447a70f60e5SJakob Hauser if (id_check != ci->devid) {
1448a70f60e5SJakob Hauser ret = dev_err_probe(dev, -ENODEV,
1449a70f60e5SJakob Hauser "device ID %02x doesn't match %s\n",
1450a70f60e5SJakob Hauser id_check, id->name);
1451de8860b1SLinus Walleij goto assert_reset;
1452de8860b1SLinus Walleij }
1453de8860b1SLinus Walleij
1454059ff0f9SJakob Hauser ret = ci->get_calibration_data(yas5xx);
1455de8860b1SLinus Walleij if (ret)
1456de8860b1SLinus Walleij goto assert_reset;
1457de8860b1SLinus Walleij
1458a70f60e5SJakob Hauser dev_info(dev, "detected %s %s\n", ci->product_name,
1459a70f60e5SJakob Hauser ci->version_names[yas5xx->version]);
1460a70f60e5SJakob Hauser
1461059ff0f9SJakob Hauser ci->dump_calibration(yas5xx);
1462059ff0f9SJakob Hauser
1463059ff0f9SJakob Hauser ret = ci->power_on(yas5xx);
1464de8860b1SLinus Walleij if (ret)
1465de8860b1SLinus Walleij goto assert_reset;
1466de8860b1SLinus Walleij
1467059ff0f9SJakob Hauser if (ci->measure_offsets) {
1468059ff0f9SJakob Hauser ret = ci->measure_offsets(yas5xx);
1469de8860b1SLinus Walleij if (ret)
1470de8860b1SLinus Walleij goto assert_reset;
1471059ff0f9SJakob Hauser }
1472de8860b1SLinus Walleij
1473de8860b1SLinus Walleij indio_dev->info = &yas5xx_info;
1474de8860b1SLinus Walleij indio_dev->available_scan_masks = yas5xx_scan_masks;
1475de8860b1SLinus Walleij indio_dev->modes = INDIO_DIRECT_MODE;
1476a70f60e5SJakob Hauser indio_dev->name = id->name;
1477de8860b1SLinus Walleij indio_dev->channels = yas5xx_channels;
1478de8860b1SLinus Walleij indio_dev->num_channels = ARRAY_SIZE(yas5xx_channels);
1479de8860b1SLinus Walleij
1480de8860b1SLinus Walleij ret = iio_triggered_buffer_setup(indio_dev, NULL,
1481de8860b1SLinus Walleij yas5xx_handle_trigger,
1482de8860b1SLinus Walleij NULL);
1483de8860b1SLinus Walleij if (ret) {
1484d05d7377SAndy Shevchenko dev_err_probe(dev, ret, "triggered buffer setup failed\n");
1485de8860b1SLinus Walleij goto assert_reset;
1486de8860b1SLinus Walleij }
1487de8860b1SLinus Walleij
1488de8860b1SLinus Walleij ret = iio_device_register(indio_dev);
1489de8860b1SLinus Walleij if (ret) {
1490d05d7377SAndy Shevchenko dev_err_probe(dev, ret, "device register failed\n");
1491de8860b1SLinus Walleij goto cleanup_buffer;
1492de8860b1SLinus Walleij }
1493de8860b1SLinus Walleij
1494de8860b1SLinus Walleij /* Take runtime PM online */
1495de8860b1SLinus Walleij pm_runtime_get_noresume(dev);
1496de8860b1SLinus Walleij pm_runtime_set_active(dev);
1497de8860b1SLinus Walleij pm_runtime_enable(dev);
1498de8860b1SLinus Walleij
1499de8860b1SLinus Walleij pm_runtime_set_autosuspend_delay(dev, YAS5XX_AUTOSUSPEND_DELAY_MS);
1500de8860b1SLinus Walleij pm_runtime_use_autosuspend(dev);
1501de8860b1SLinus Walleij pm_runtime_put(dev);
1502de8860b1SLinus Walleij
1503de8860b1SLinus Walleij return 0;
1504de8860b1SLinus Walleij
1505de8860b1SLinus Walleij cleanup_buffer:
1506de8860b1SLinus Walleij iio_triggered_buffer_cleanup(indio_dev);
1507de8860b1SLinus Walleij assert_reset:
1508de8860b1SLinus Walleij gpiod_set_value_cansleep(yas5xx->reset, 1);
1509de8860b1SLinus Walleij reg_off:
1510de8860b1SLinus Walleij regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
1511de8860b1SLinus Walleij
1512de8860b1SLinus Walleij return ret;
1513de8860b1SLinus Walleij }
1514de8860b1SLinus Walleij
yas5xx_remove(struct i2c_client * i2c)1515ed5c2f5fSUwe Kleine-König static void yas5xx_remove(struct i2c_client *i2c)
1516de8860b1SLinus Walleij {
1517de8860b1SLinus Walleij struct iio_dev *indio_dev = i2c_get_clientdata(i2c);
1518de8860b1SLinus Walleij struct yas5xx *yas5xx = iio_priv(indio_dev);
1519de8860b1SLinus Walleij struct device *dev = &i2c->dev;
1520de8860b1SLinus Walleij
1521de8860b1SLinus Walleij iio_device_unregister(indio_dev);
1522de8860b1SLinus Walleij iio_triggered_buffer_cleanup(indio_dev);
1523de8860b1SLinus Walleij /*
1524de8860b1SLinus Walleij * Now we can't get any more reads from the device, which would
1525de8860b1SLinus Walleij * also call pm_runtime* functions and race with our disable
1526de8860b1SLinus Walleij * code. Disable PM runtime in orderly fashion and power down.
1527de8860b1SLinus Walleij */
1528de8860b1SLinus Walleij pm_runtime_get_sync(dev);
1529de8860b1SLinus Walleij pm_runtime_put_noidle(dev);
1530de8860b1SLinus Walleij pm_runtime_disable(dev);
1531de8860b1SLinus Walleij gpiod_set_value_cansleep(yas5xx->reset, 1);
1532de8860b1SLinus Walleij regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
1533de8860b1SLinus Walleij }
1534de8860b1SLinus Walleij
yas5xx_runtime_suspend(struct device * dev)1535e5933cf4SJonathan Cameron static int yas5xx_runtime_suspend(struct device *dev)
1536de8860b1SLinus Walleij {
1537de8860b1SLinus Walleij struct iio_dev *indio_dev = dev_get_drvdata(dev);
1538de8860b1SLinus Walleij struct yas5xx *yas5xx = iio_priv(indio_dev);
1539de8860b1SLinus Walleij
1540de8860b1SLinus Walleij gpiod_set_value_cansleep(yas5xx->reset, 1);
1541de8860b1SLinus Walleij regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
1542de8860b1SLinus Walleij
1543de8860b1SLinus Walleij return 0;
1544de8860b1SLinus Walleij }
1545de8860b1SLinus Walleij
yas5xx_runtime_resume(struct device * dev)1546e5933cf4SJonathan Cameron static int yas5xx_runtime_resume(struct device *dev)
1547de8860b1SLinus Walleij {
1548de8860b1SLinus Walleij struct iio_dev *indio_dev = dev_get_drvdata(dev);
1549de8860b1SLinus Walleij struct yas5xx *yas5xx = iio_priv(indio_dev);
1550059ff0f9SJakob Hauser const struct yas5xx_chip_info *ci = yas5xx->chip_info;
1551de8860b1SLinus Walleij int ret;
1552de8860b1SLinus Walleij
1553de8860b1SLinus Walleij ret = regulator_bulk_enable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
1554de8860b1SLinus Walleij if (ret) {
1555de8860b1SLinus Walleij dev_err(dev, "cannot enable regulators\n");
1556de8860b1SLinus Walleij return ret;
1557de8860b1SLinus Walleij }
1558de8860b1SLinus Walleij
1559de8860b1SLinus Walleij /*
1560de8860b1SLinus Walleij * The YAS530 datasheet says TVSKW is up to 30 ms, after that 1 ms
1561de8860b1SLinus Walleij * for all voltages to settle. The YAS532 is 10ms then 4ms for the
1562de8860b1SLinus Walleij * I2C to come online. Let's keep it safe and put this at 31ms.
1563de8860b1SLinus Walleij */
1564de8860b1SLinus Walleij usleep_range(31000, 40000);
1565de8860b1SLinus Walleij gpiod_set_value_cansleep(yas5xx->reset, 0);
1566de8860b1SLinus Walleij
1567059ff0f9SJakob Hauser ret = ci->power_on(yas5xx);
1568de8860b1SLinus Walleij if (ret) {
1569de8860b1SLinus Walleij dev_err(dev, "cannot power on\n");
1570de8860b1SLinus Walleij goto out_reset;
1571de8860b1SLinus Walleij }
1572de8860b1SLinus Walleij
1573de8860b1SLinus Walleij return 0;
1574de8860b1SLinus Walleij
1575de8860b1SLinus Walleij out_reset:
1576de8860b1SLinus Walleij gpiod_set_value_cansleep(yas5xx->reset, 1);
1577de8860b1SLinus Walleij regulator_bulk_disable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs);
1578de8860b1SLinus Walleij
1579de8860b1SLinus Walleij return ret;
1580de8860b1SLinus Walleij }
1581de8860b1SLinus Walleij
1582e5933cf4SJonathan Cameron static DEFINE_RUNTIME_DEV_PM_OPS(yas5xx_dev_pm_ops, yas5xx_runtime_suspend,
1583e5933cf4SJonathan Cameron yas5xx_runtime_resume, NULL);
1584de8860b1SLinus Walleij
1585de8860b1SLinus Walleij static const struct i2c_device_id yas5xx_id[] = {
1586741d1e37SAndy Shevchenko {"yas530", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas530] },
1587741d1e37SAndy Shevchenko {"yas532", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] },
1588741d1e37SAndy Shevchenko {"yas533", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] },
1589741d1e37SAndy Shevchenko {"yas537", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] },
1590de8860b1SLinus Walleij {}
1591de8860b1SLinus Walleij };
1592de8860b1SLinus Walleij MODULE_DEVICE_TABLE(i2c, yas5xx_id);
1593de8860b1SLinus Walleij
1594de8860b1SLinus Walleij static const struct of_device_id yas5xx_of_match[] = {
1595741d1e37SAndy Shevchenko { .compatible = "yamaha,yas530", &yas5xx_chip_info_tbl[yas530] },
1596741d1e37SAndy Shevchenko { .compatible = "yamaha,yas532", &yas5xx_chip_info_tbl[yas532] },
1597741d1e37SAndy Shevchenko { .compatible = "yamaha,yas533", &yas5xx_chip_info_tbl[yas533] },
1598741d1e37SAndy Shevchenko { .compatible = "yamaha,yas537", &yas5xx_chip_info_tbl[yas537] },
1599de8860b1SLinus Walleij {}
1600de8860b1SLinus Walleij };
1601de8860b1SLinus Walleij MODULE_DEVICE_TABLE(of, yas5xx_of_match);
1602de8860b1SLinus Walleij
1603de8860b1SLinus Walleij static struct i2c_driver yas5xx_driver = {
1604de8860b1SLinus Walleij .driver = {
1605de8860b1SLinus Walleij .name = "yas5xx",
1606de8860b1SLinus Walleij .of_match_table = yas5xx_of_match,
1607e5933cf4SJonathan Cameron .pm = pm_ptr(&yas5xx_dev_pm_ops),
1608de8860b1SLinus Walleij },
16097cf15f42SUwe Kleine-König .probe = yas5xx_probe,
1610de8860b1SLinus Walleij .remove = yas5xx_remove,
1611de8860b1SLinus Walleij .id_table = yas5xx_id,
1612de8860b1SLinus Walleij };
1613de8860b1SLinus Walleij module_i2c_driver(yas5xx_driver);
1614de8860b1SLinus Walleij
1615de8860b1SLinus Walleij MODULE_DESCRIPTION("Yamaha YAS53x 3-axis magnetometer driver");
1616de8860b1SLinus Walleij MODULE_AUTHOR("Linus Walleij");
1617de8860b1SLinus Walleij MODULE_LICENSE("GPL v2");
1618