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