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