1*8dc6d241SJorijn van der Graaf // SPDX-License-Identifier: GPL-2.0-only 2*8dc6d241SJorijn van der Graaf /* 3*8dc6d241SJorijn van der Graaf * Support for QST QMC6308 3-Axis Magnetic Sensor on I2C bus. 4*8dc6d241SJorijn van der Graaf * 5*8dc6d241SJorijn van der Graaf * Copyright (C) 2026 Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net> 6*8dc6d241SJorijn van der Graaf * 7*8dc6d241SJorijn van der Graaf * Datasheet available at 8*8dc6d241SJorijn van der Graaf * <https://qstcorp.com/upload/pdf/202202/13-52-15%20QMC6308%20Datasheet%20Rev.%20F(1).pdf> 9*8dc6d241SJorijn van der Graaf */ 10*8dc6d241SJorijn van der Graaf 11*8dc6d241SJorijn van der Graaf #include <linux/array_size.h> 12*8dc6d241SJorijn van der Graaf #include <linux/bitfield.h> 13*8dc6d241SJorijn van der Graaf #include <linux/bits.h> 14*8dc6d241SJorijn van der Graaf #include <linux/cleanup.h> 15*8dc6d241SJorijn van der Graaf #include <linux/delay.h> 16*8dc6d241SJorijn van der Graaf #include <linux/dev_printk.h> 17*8dc6d241SJorijn van der Graaf #include <linux/err.h> 18*8dc6d241SJorijn van der Graaf #include <linux/i2c.h> 19*8dc6d241SJorijn van der Graaf #include <linux/module.h> 20*8dc6d241SJorijn van der Graaf #include <linux/mutex.h> 21*8dc6d241SJorijn van der Graaf #include <linux/pm_runtime.h> 22*8dc6d241SJorijn van der Graaf #include <linux/regmap.h> 23*8dc6d241SJorijn van der Graaf #include <linux/regulator/consumer.h> 24*8dc6d241SJorijn van der Graaf #include <linux/time.h> 25*8dc6d241SJorijn van der Graaf #include <linux/types.h> 26*8dc6d241SJorijn van der Graaf 27*8dc6d241SJorijn van der Graaf #include <asm/byteorder.h> 28*8dc6d241SJorijn van der Graaf 29*8dc6d241SJorijn van der Graaf #include <linux/iio/iio.h> 30*8dc6d241SJorijn van der Graaf 31*8dc6d241SJorijn van der Graaf #define QMC6308_REG_ID 0x00 32*8dc6d241SJorijn van der Graaf #define QMC6308_REG_X_LSB 0x01 33*8dc6d241SJorijn van der Graaf #define QMC6308_REG_STATUS 0x09 34*8dc6d241SJorijn van der Graaf #define QMC6308_REG_CTRL1 0x0A 35*8dc6d241SJorijn van der Graaf #define QMC6308_REG_CTRL2 0x0B 36*8dc6d241SJorijn van der Graaf #define QMC6308_REG_CTRL3 0x0D 37*8dc6d241SJorijn van der Graaf #define QMC6308_REG_CTRL4 0x29 38*8dc6d241SJorijn van der Graaf 39*8dc6d241SJorijn van der Graaf #define QMC6308_CHIP_ID 0x80 40*8dc6d241SJorijn van der Graaf 41*8dc6d241SJorijn van der Graaf /* Control register 1 */ 42*8dc6d241SJorijn van der Graaf #define QMC6308_MODE_MASK GENMASK(1, 0) 43*8dc6d241SJorijn van der Graaf #define QMC6308_ODR_MASK GENMASK(3, 2) 44*8dc6d241SJorijn van der Graaf #define QMC6308_OSR1_MASK GENMASK(5, 4) 45*8dc6d241SJorijn van der Graaf #define QMC6308_OSR2_MASK GENMASK(7, 6) 46*8dc6d241SJorijn van der Graaf 47*8dc6d241SJorijn van der Graaf #define QMC6308_MODE_SUSPEND 0x00 48*8dc6d241SJorijn van der Graaf #define QMC6308_MODE_NORMAL 0x01 49*8dc6d241SJorijn van der Graaf 50*8dc6d241SJorijn van der Graaf #define QMC6308_ODR_10HZ 0x00 51*8dc6d241SJorijn van der Graaf #define QMC6308_ODR_50HZ 0x01 52*8dc6d241SJorijn van der Graaf #define QMC6308_ODR_100HZ 0x02 53*8dc6d241SJorijn van der Graaf #define QMC6308_ODR_200HZ 0x03 54*8dc6d241SJorijn van der Graaf 55*8dc6d241SJorijn van der Graaf #define QMC6308_OSR1_8 0x00 56*8dc6d241SJorijn van der Graaf #define QMC6308_OSR1_4 0x01 57*8dc6d241SJorijn van der Graaf #define QMC6308_OSR1_2 0x02 58*8dc6d241SJorijn van der Graaf #define QMC6308_OSR1_1 0x03 59*8dc6d241SJorijn van der Graaf 60*8dc6d241SJorijn van der Graaf /* Control register 2 */ 61*8dc6d241SJorijn van der Graaf #define QMC6308_SET_RESET_MASK GENMASK(1, 0) 62*8dc6d241SJorijn van der Graaf #define QMC6308_RNG_MASK GENMASK(3, 2) 63*8dc6d241SJorijn van der Graaf #define QMC6308_SELF_TEST BIT(6) 64*8dc6d241SJorijn van der Graaf #define QMC6308_SOFT_RST BIT(7) 65*8dc6d241SJorijn van der Graaf 66*8dc6d241SJorijn van der Graaf #define QMC6308_SET_RESET_ON 0x00 67*8dc6d241SJorijn van der Graaf 68*8dc6d241SJorijn van der Graaf #define QMC6308_RNG_30G 0x00 69*8dc6d241SJorijn van der Graaf #define QMC6308_RNG_12G 0x01 70*8dc6d241SJorijn van der Graaf #define QMC6308_RNG_8G 0x02 71*8dc6d241SJorijn van der Graaf #define QMC6308_RNG_2G 0x03 72*8dc6d241SJorijn van der Graaf 73*8dc6d241SJorijn van der Graaf /* Status register */ 74*8dc6d241SJorijn van der Graaf #define QMC6308_STATUS_DRDY BIT(0) 75*8dc6d241SJorijn van der Graaf #define QMC6308_STATUS_OVFL BIT(1) 76*8dc6d241SJorijn van der Graaf 77*8dc6d241SJorijn van der Graaf /* Power-on completion time (datasheet Table 7) */ 78*8dc6d241SJorijn van der Graaf #define QMC6308_POR_US 250 79*8dc6d241SJorijn van der Graaf 80*8dc6d241SJorijn van der Graaf #define QMC6308_AUTOSUSPEND_DELAY_MS 500 81*8dc6d241SJorijn van der Graaf 82*8dc6d241SJorijn van der Graaf struct qmc6308_data { 83*8dc6d241SJorijn van der Graaf struct regmap *regmap; 84*8dc6d241SJorijn van der Graaf /* Protect data->range/odr/osr and serialize measurements */ 85*8dc6d241SJorijn van der Graaf struct mutex mutex; 86*8dc6d241SJorijn van der Graaf struct iio_mount_matrix orientation; 87*8dc6d241SJorijn van der Graaf u8 range; 88*8dc6d241SJorijn van der Graaf u8 odr; 89*8dc6d241SJorijn van der Graaf u8 osr; 90*8dc6d241SJorijn van der Graaf }; 91*8dc6d241SJorijn van der Graaf 92*8dc6d241SJorijn van der Graaf enum qmc6308_axis { 93*8dc6d241SJorijn van der Graaf QMC6308_AXIS_X, 94*8dc6d241SJorijn van der Graaf QMC6308_AXIS_Y, 95*8dc6d241SJorijn van der Graaf QMC6308_AXIS_Z, 96*8dc6d241SJorijn van der Graaf }; 97*8dc6d241SJorijn van der Graaf 98*8dc6d241SJorijn van der Graaf static const int qmc6308_odr_avail[] = { 99*8dc6d241SJorijn van der Graaf [QMC6308_ODR_10HZ] = 10, 100*8dc6d241SJorijn van der Graaf [QMC6308_ODR_50HZ] = 50, 101*8dc6d241SJorijn van der Graaf [QMC6308_ODR_100HZ] = 100, 102*8dc6d241SJorijn van der Graaf [QMC6308_ODR_200HZ] = 200, 103*8dc6d241SJorijn van der Graaf }; 104*8dc6d241SJorijn van der Graaf 105*8dc6d241SJorijn van der Graaf static const int qmc6308_osr1_avail[] = { 106*8dc6d241SJorijn van der Graaf [QMC6308_OSR1_8] = 8, 107*8dc6d241SJorijn van der Graaf [QMC6308_OSR1_4] = 4, 108*8dc6d241SJorijn van der Graaf [QMC6308_OSR1_2] = 2, 109*8dc6d241SJorijn van der Graaf [QMC6308_OSR1_1] = 1, 110*8dc6d241SJorijn van der Graaf }; 111*8dc6d241SJorijn van der Graaf 112*8dc6d241SJorijn van der Graaf /* 113*8dc6d241SJorijn van der Graaf * Sensitivity is 1000/2500/3750/15000 LSB/Gauss for the 114*8dc6d241SJorijn van der Graaf * +-30/12/8/2 Gauss ranges respectively. 115*8dc6d241SJorijn van der Graaf */ 116*8dc6d241SJorijn van der Graaf static const int qmc6308_scales[][2] = { 117*8dc6d241SJorijn van der Graaf [QMC6308_RNG_30G] = { 0, 1000000 }, 118*8dc6d241SJorijn van der Graaf [QMC6308_RNG_12G] = { 0, 400000 }, 119*8dc6d241SJorijn van der Graaf [QMC6308_RNG_8G] = { 0, 266667 }, 120*8dc6d241SJorijn van der Graaf [QMC6308_RNG_2G] = { 0, 66667 }, 121*8dc6d241SJorijn van der Graaf }; 122*8dc6d241SJorijn van der Graaf 123*8dc6d241SJorijn van der Graaf static int qmc6308_set_mode(struct qmc6308_data *data, unsigned int mode) 124*8dc6d241SJorijn van der Graaf { 125*8dc6d241SJorijn van der Graaf return regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, 126*8dc6d241SJorijn van der Graaf QMC6308_MODE_MASK, 127*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_MODE_MASK, mode)); 128*8dc6d241SJorijn van der Graaf } 129*8dc6d241SJorijn van der Graaf 130*8dc6d241SJorijn van der Graaf static int qmc6308_take_measurement(struct iio_dev *indio_dev, int index, 131*8dc6d241SJorijn van der Graaf int *val) 132*8dc6d241SJorijn van der Graaf { 133*8dc6d241SJorijn van der Graaf struct qmc6308_data *data = iio_priv(indio_dev); 134*8dc6d241SJorijn van der Graaf struct device *dev = regmap_get_device(data->regmap); 135*8dc6d241SJorijn van der Graaf unsigned int status; 136*8dc6d241SJorijn van der Graaf __le16 buf[3]; 137*8dc6d241SJorijn van der Graaf int ret; 138*8dc6d241SJorijn van der Graaf 139*8dc6d241SJorijn van der Graaf PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm); 140*8dc6d241SJorijn van der Graaf ret = PM_RUNTIME_ACQUIRE_ERR(&pm); 141*8dc6d241SJorijn van der Graaf if (ret) { 142*8dc6d241SJorijn van der Graaf dev_err(dev, "Failed to power on (%d)\n", ret); 143*8dc6d241SJorijn van der Graaf return ret; 144*8dc6d241SJorijn van der Graaf } 145*8dc6d241SJorijn van der Graaf 146*8dc6d241SJorijn van der Graaf guard(mutex)(&data->mutex); 147*8dc6d241SJorijn van der Graaf 148*8dc6d241SJorijn van der Graaf /* 149*8dc6d241SJorijn van der Graaf * Reading the status register clears DRDY, which is why the poll 150*8dc6d241SJorijn van der Graaf * and the data read stay under one mutex hold. A runtime resume 151*8dc6d241SJorijn van der Graaf * clears DRDY too, so a sample converted before the last suspend 152*8dc6d241SJorijn van der Graaf * is never returned here. 153*8dc6d241SJorijn van der Graaf * 154*8dc6d241SJorijn van der Graaf * The timeout is 50ms of headroom over the slowest ODR (10Hz). 155*8dc6d241SJorijn van der Graaf */ 156*8dc6d241SJorijn van der Graaf ret = regmap_read_poll_timeout(data->regmap, QMC6308_REG_STATUS, 157*8dc6d241SJorijn van der Graaf status, (status & QMC6308_STATUS_DRDY), 158*8dc6d241SJorijn van der Graaf 2 * USEC_PER_MSEC, 159*8dc6d241SJorijn van der Graaf 150 * USEC_PER_MSEC); 160*8dc6d241SJorijn van der Graaf if (ret) 161*8dc6d241SJorijn van der Graaf return ret; 162*8dc6d241SJorijn van der Graaf 163*8dc6d241SJorijn van der Graaf ret = regmap_bulk_read(data->regmap, QMC6308_REG_X_LSB, buf, 164*8dc6d241SJorijn van der Graaf sizeof(buf)); 165*8dc6d241SJorijn van der Graaf if (ret) 166*8dc6d241SJorijn van der Graaf return ret; 167*8dc6d241SJorijn van der Graaf 168*8dc6d241SJorijn van der Graaf if (status & QMC6308_STATUS_OVFL) 169*8dc6d241SJorijn van der Graaf return -ERANGE; 170*8dc6d241SJorijn van der Graaf 171*8dc6d241SJorijn van der Graaf *val = (s16)le16_to_cpu(buf[index]); 172*8dc6d241SJorijn van der Graaf 173*8dc6d241SJorijn van der Graaf return 0; 174*8dc6d241SJorijn van der Graaf } 175*8dc6d241SJorijn van der Graaf 176*8dc6d241SJorijn van der Graaf static int qmc6308_read_raw(struct iio_dev *indio_dev, 177*8dc6d241SJorijn van der Graaf const struct iio_chan_spec *chan, 178*8dc6d241SJorijn van der Graaf int *val, int *val2, long mask) 179*8dc6d241SJorijn van der Graaf { 180*8dc6d241SJorijn van der Graaf struct qmc6308_data *data = iio_priv(indio_dev); 181*8dc6d241SJorijn van der Graaf int ret; 182*8dc6d241SJorijn van der Graaf 183*8dc6d241SJorijn van der Graaf switch (mask) { 184*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_RAW: 185*8dc6d241SJorijn van der Graaf ret = qmc6308_take_measurement(indio_dev, chan->address, val); 186*8dc6d241SJorijn van der Graaf if (ret) 187*8dc6d241SJorijn van der Graaf return ret; 188*8dc6d241SJorijn van der Graaf return IIO_VAL_INT; 189*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_SCALE: { 190*8dc6d241SJorijn van der Graaf guard(mutex)(&data->mutex); 191*8dc6d241SJorijn van der Graaf 192*8dc6d241SJorijn van der Graaf *val = qmc6308_scales[data->range][0]; 193*8dc6d241SJorijn van der Graaf *val2 = qmc6308_scales[data->range][1]; 194*8dc6d241SJorijn van der Graaf 195*8dc6d241SJorijn van der Graaf return IIO_VAL_INT_PLUS_NANO; 196*8dc6d241SJorijn van der Graaf } 197*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_SAMP_FREQ: { 198*8dc6d241SJorijn van der Graaf guard(mutex)(&data->mutex); 199*8dc6d241SJorijn van der Graaf 200*8dc6d241SJorijn van der Graaf *val = qmc6308_odr_avail[data->odr]; 201*8dc6d241SJorijn van der Graaf 202*8dc6d241SJorijn van der Graaf return IIO_VAL_INT; 203*8dc6d241SJorijn van der Graaf } 204*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { 205*8dc6d241SJorijn van der Graaf guard(mutex)(&data->mutex); 206*8dc6d241SJorijn van der Graaf 207*8dc6d241SJorijn van der Graaf *val = qmc6308_osr1_avail[data->osr]; 208*8dc6d241SJorijn van der Graaf 209*8dc6d241SJorijn van der Graaf return IIO_VAL_INT; 210*8dc6d241SJorijn van der Graaf } 211*8dc6d241SJorijn van der Graaf default: 212*8dc6d241SJorijn van der Graaf return -EINVAL; 213*8dc6d241SJorijn van der Graaf } 214*8dc6d241SJorijn van der Graaf } 215*8dc6d241SJorijn van der Graaf 216*8dc6d241SJorijn van der Graaf static int qmc6308_write_raw(struct iio_dev *indio_dev, 217*8dc6d241SJorijn van der Graaf const struct iio_chan_spec *chan, 218*8dc6d241SJorijn van der Graaf int val, int val2, long mask) 219*8dc6d241SJorijn van der Graaf { 220*8dc6d241SJorijn van der Graaf struct qmc6308_data *data = iio_priv(indio_dev); 221*8dc6d241SJorijn van der Graaf unsigned int status; 222*8dc6d241SJorijn van der Graaf unsigned int i; 223*8dc6d241SJorijn van der Graaf int ret; 224*8dc6d241SJorijn van der Graaf 225*8dc6d241SJorijn van der Graaf switch (mask) { 226*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_SCALE: { 227*8dc6d241SJorijn van der Graaf if (val != 0) 228*8dc6d241SJorijn van der Graaf return -EINVAL; 229*8dc6d241SJorijn van der Graaf 230*8dc6d241SJorijn van der Graaf for (i = 0; i < ARRAY_SIZE(qmc6308_scales); i++) { 231*8dc6d241SJorijn van der Graaf if (val2 == qmc6308_scales[i][1]) 232*8dc6d241SJorijn van der Graaf break; 233*8dc6d241SJorijn van der Graaf } 234*8dc6d241SJorijn van der Graaf if (i == ARRAY_SIZE(qmc6308_scales)) 235*8dc6d241SJorijn van der Graaf return -EINVAL; 236*8dc6d241SJorijn van der Graaf 237*8dc6d241SJorijn van der Graaf guard(mutex)(&data->mutex); 238*8dc6d241SJorijn van der Graaf 239*8dc6d241SJorijn van der Graaf ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL2, 240*8dc6d241SJorijn van der Graaf QMC6308_RNG_MASK, 241*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_RNG_MASK, i)); 242*8dc6d241SJorijn van der Graaf if (ret) 243*8dc6d241SJorijn van der Graaf return ret; 244*8dc6d241SJorijn van der Graaf 245*8dc6d241SJorijn van der Graaf data->range = i; 246*8dc6d241SJorijn van der Graaf 247*8dc6d241SJorijn van der Graaf /* 248*8dc6d241SJorijn van der Graaf * The data registers still hold (and DRDY still 249*8dc6d241SJorijn van der Graaf * advertises) a sample converted at the previous range; 250*8dc6d241SJorijn van der Graaf * discard it so that a read does not pair old-range data 251*8dc6d241SJorijn van der Graaf * with the new scale. A conversion already in flight may 252*8dc6d241SJorijn van der Graaf * still complete at the old range, so this narrows the 253*8dc6d241SJorijn van der Graaf * window rather than closing it. The range change itself 254*8dc6d241SJorijn van der Graaf * took effect, so only log a failure here: an error 255*8dc6d241SJorijn van der Graaf * would mislead userspace about an effective write. 256*8dc6d241SJorijn van der Graaf */ 257*8dc6d241SJorijn van der Graaf ret = regmap_read(data->regmap, QMC6308_REG_STATUS, 258*8dc6d241SJorijn van der Graaf &status); 259*8dc6d241SJorijn van der Graaf if (ret) 260*8dc6d241SJorijn van der Graaf dev_warn(regmap_get_device(data->regmap), 261*8dc6d241SJorijn van der Graaf "Failed to discard stale sample (%d)\n", ret); 262*8dc6d241SJorijn van der Graaf 263*8dc6d241SJorijn van der Graaf return 0; 264*8dc6d241SJorijn van der Graaf } 265*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_SAMP_FREQ: { 266*8dc6d241SJorijn van der Graaf for (i = 0; i < ARRAY_SIZE(qmc6308_odr_avail); i++) { 267*8dc6d241SJorijn van der Graaf if (val == qmc6308_odr_avail[i]) 268*8dc6d241SJorijn van der Graaf break; 269*8dc6d241SJorijn van der Graaf } 270*8dc6d241SJorijn van der Graaf if (i == ARRAY_SIZE(qmc6308_odr_avail)) 271*8dc6d241SJorijn van der Graaf return -EINVAL; 272*8dc6d241SJorijn van der Graaf 273*8dc6d241SJorijn van der Graaf guard(mutex)(&data->mutex); 274*8dc6d241SJorijn van der Graaf 275*8dc6d241SJorijn van der Graaf ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, 276*8dc6d241SJorijn van der Graaf QMC6308_ODR_MASK, 277*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_ODR_MASK, i)); 278*8dc6d241SJorijn van der Graaf if (ret) 279*8dc6d241SJorijn van der Graaf return ret; 280*8dc6d241SJorijn van der Graaf 281*8dc6d241SJorijn van der Graaf data->odr = i; 282*8dc6d241SJorijn van der Graaf 283*8dc6d241SJorijn van der Graaf return 0; 284*8dc6d241SJorijn van der Graaf } 285*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { 286*8dc6d241SJorijn van der Graaf for (i = 0; i < ARRAY_SIZE(qmc6308_osr1_avail); i++) { 287*8dc6d241SJorijn van der Graaf if (val == qmc6308_osr1_avail[i]) 288*8dc6d241SJorijn van der Graaf break; 289*8dc6d241SJorijn van der Graaf } 290*8dc6d241SJorijn van der Graaf if (i == ARRAY_SIZE(qmc6308_osr1_avail)) 291*8dc6d241SJorijn van der Graaf return -EINVAL; 292*8dc6d241SJorijn van der Graaf 293*8dc6d241SJorijn van der Graaf guard(mutex)(&data->mutex); 294*8dc6d241SJorijn van der Graaf 295*8dc6d241SJorijn van der Graaf ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, 296*8dc6d241SJorijn van der Graaf QMC6308_OSR1_MASK, 297*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_OSR1_MASK, i)); 298*8dc6d241SJorijn van der Graaf if (ret) 299*8dc6d241SJorijn van der Graaf return ret; 300*8dc6d241SJorijn van der Graaf 301*8dc6d241SJorijn van der Graaf data->osr = i; 302*8dc6d241SJorijn van der Graaf 303*8dc6d241SJorijn van der Graaf return 0; 304*8dc6d241SJorijn van der Graaf } 305*8dc6d241SJorijn van der Graaf default: 306*8dc6d241SJorijn van der Graaf return -EINVAL; 307*8dc6d241SJorijn van der Graaf } 308*8dc6d241SJorijn van der Graaf } 309*8dc6d241SJorijn van der Graaf 310*8dc6d241SJorijn van der Graaf static int qmc6308_read_avail(struct iio_dev *indio_dev, 311*8dc6d241SJorijn van der Graaf struct iio_chan_spec const *chan, 312*8dc6d241SJorijn van der Graaf const int **vals, int *type, int *length, 313*8dc6d241SJorijn van der Graaf long mask) 314*8dc6d241SJorijn van der Graaf { 315*8dc6d241SJorijn van der Graaf switch (mask) { 316*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_SAMP_FREQ: 317*8dc6d241SJorijn van der Graaf *vals = qmc6308_odr_avail; 318*8dc6d241SJorijn van der Graaf *type = IIO_VAL_INT; 319*8dc6d241SJorijn van der Graaf *length = ARRAY_SIZE(qmc6308_odr_avail); 320*8dc6d241SJorijn van der Graaf return IIO_AVAIL_LIST; 321*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 322*8dc6d241SJorijn van der Graaf *vals = qmc6308_osr1_avail; 323*8dc6d241SJorijn van der Graaf *type = IIO_VAL_INT; 324*8dc6d241SJorijn van der Graaf *length = ARRAY_SIZE(qmc6308_osr1_avail); 325*8dc6d241SJorijn van der Graaf return IIO_AVAIL_LIST; 326*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_SCALE: 327*8dc6d241SJorijn van der Graaf *vals = (const int *)qmc6308_scales; 328*8dc6d241SJorijn van der Graaf *type = IIO_VAL_INT_PLUS_NANO; 329*8dc6d241SJorijn van der Graaf *length = ARRAY_SIZE(qmc6308_scales) * 2; 330*8dc6d241SJorijn van der Graaf return IIO_AVAIL_LIST; 331*8dc6d241SJorijn van der Graaf default: 332*8dc6d241SJorijn van der Graaf return -EINVAL; 333*8dc6d241SJorijn van der Graaf } 334*8dc6d241SJorijn van der Graaf } 335*8dc6d241SJorijn van der Graaf 336*8dc6d241SJorijn van der Graaf static int qmc6308_write_raw_get_fmt(struct iio_dev *indio_dev, 337*8dc6d241SJorijn van der Graaf struct iio_chan_spec const *chan, 338*8dc6d241SJorijn van der Graaf long mask) 339*8dc6d241SJorijn van der Graaf { 340*8dc6d241SJorijn van der Graaf switch (mask) { 341*8dc6d241SJorijn van der Graaf case IIO_CHAN_INFO_SCALE: 342*8dc6d241SJorijn van der Graaf return IIO_VAL_INT_PLUS_NANO; 343*8dc6d241SJorijn van der Graaf default: 344*8dc6d241SJorijn van der Graaf return IIO_VAL_INT; 345*8dc6d241SJorijn van der Graaf } 346*8dc6d241SJorijn van der Graaf } 347*8dc6d241SJorijn van der Graaf 348*8dc6d241SJorijn van der Graaf static const struct iio_mount_matrix * 349*8dc6d241SJorijn van der Graaf qmc6308_get_mount_matrix(const struct iio_dev *indio_dev, 350*8dc6d241SJorijn van der Graaf const struct iio_chan_spec *chan) 351*8dc6d241SJorijn van der Graaf { 352*8dc6d241SJorijn van der Graaf struct qmc6308_data *data = iio_priv(indio_dev); 353*8dc6d241SJorijn van der Graaf 354*8dc6d241SJorijn van der Graaf return &data->orientation; 355*8dc6d241SJorijn van der Graaf } 356*8dc6d241SJorijn van der Graaf 357*8dc6d241SJorijn van der Graaf static const struct iio_chan_spec_ext_info qmc6308_ext_info[] = { 358*8dc6d241SJorijn van der Graaf IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, qmc6308_get_mount_matrix), 359*8dc6d241SJorijn van der Graaf { } 360*8dc6d241SJorijn van der Graaf }; 361*8dc6d241SJorijn van der Graaf 362*8dc6d241SJorijn van der Graaf static const struct iio_info qmc6308_info = { 363*8dc6d241SJorijn van der Graaf .read_raw = qmc6308_read_raw, 364*8dc6d241SJorijn van der Graaf .write_raw = qmc6308_write_raw, 365*8dc6d241SJorijn van der Graaf .read_avail = qmc6308_read_avail, 366*8dc6d241SJorijn van der Graaf .write_raw_get_fmt = qmc6308_write_raw_get_fmt, 367*8dc6d241SJorijn van der Graaf }; 368*8dc6d241SJorijn van der Graaf 369*8dc6d241SJorijn van der Graaf static int qmc6308_init(struct qmc6308_data *data) 370*8dc6d241SJorijn van der Graaf { 371*8dc6d241SJorijn van der Graaf struct regmap *map = data->regmap; 372*8dc6d241SJorijn van der Graaf unsigned int reg; 373*8dc6d241SJorijn van der Graaf int ret; 374*8dc6d241SJorijn van der Graaf 375*8dc6d241SJorijn van der Graaf ret = regmap_read(map, QMC6308_REG_ID, ®); 376*8dc6d241SJorijn van der Graaf if (ret) 377*8dc6d241SJorijn van der Graaf return ret; 378*8dc6d241SJorijn van der Graaf 379*8dc6d241SJorijn van der Graaf /* Allow unknown IDs so that fallback compatibles work */ 380*8dc6d241SJorijn van der Graaf if (reg != QMC6308_CHIP_ID) 381*8dc6d241SJorijn van der Graaf dev_warn(regmap_get_device(map), 382*8dc6d241SJorijn van der Graaf "Unknown chip id: 0x%02x, continuing\n", reg); 383*8dc6d241SJorijn van der Graaf 384*8dc6d241SJorijn van der Graaf /* The SOFT_RST bit is not auto-cleared and must be written back 0 */ 385*8dc6d241SJorijn van der Graaf ret = regmap_write(map, QMC6308_REG_CTRL2, QMC6308_SOFT_RST); 386*8dc6d241SJorijn van der Graaf if (ret) 387*8dc6d241SJorijn van der Graaf return ret; 388*8dc6d241SJorijn van der Graaf 389*8dc6d241SJorijn van der Graaf /* 390*8dc6d241SJorijn van der Graaf * The datasheet gives no soft-reset completion figure; reuse the 391*8dc6d241SJorijn van der Graaf * power-on time as a conservative bound. 392*8dc6d241SJorijn van der Graaf */ 393*8dc6d241SJorijn van der Graaf fsleep(QMC6308_POR_US); 394*8dc6d241SJorijn van der Graaf 395*8dc6d241SJorijn van der Graaf data->range = QMC6308_RNG_30G; 396*8dc6d241SJorijn van der Graaf data->odr = QMC6308_ODR_50HZ; 397*8dc6d241SJorijn van der Graaf data->osr = QMC6308_OSR1_8; 398*8dc6d241SJorijn van der Graaf 399*8dc6d241SJorijn van der Graaf ret = regmap_write(map, QMC6308_REG_CTRL2, 400*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_SET_RESET_MASK, 401*8dc6d241SJorijn van der Graaf QMC6308_SET_RESET_ON) | 402*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_RNG_MASK, data->range)); 403*8dc6d241SJorijn van der Graaf if (ret) 404*8dc6d241SJorijn van der Graaf return ret; 405*8dc6d241SJorijn van der Graaf 406*8dc6d241SJorijn van der Graaf /* OSR2 (second-stage filter) set to its power-on default of 0 */ 407*8dc6d241SJorijn van der Graaf return regmap_write(map, QMC6308_REG_CTRL1, 408*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_MODE_MASK, 409*8dc6d241SJorijn van der Graaf QMC6308_MODE_NORMAL) | 410*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_ODR_MASK, data->odr) | 411*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_OSR1_MASK, data->osr) | 412*8dc6d241SJorijn van der Graaf FIELD_PREP(QMC6308_OSR2_MASK, 0)); 413*8dc6d241SJorijn van der Graaf } 414*8dc6d241SJorijn van der Graaf 415*8dc6d241SJorijn van der Graaf static void qmc6308_power_down_action(void *priv) 416*8dc6d241SJorijn van der Graaf { 417*8dc6d241SJorijn van der Graaf struct qmc6308_data *data = priv; 418*8dc6d241SJorijn van der Graaf 419*8dc6d241SJorijn van der Graaf if (!pm_runtime_status_suspended(regmap_get_device(data->regmap))) 420*8dc6d241SJorijn van der Graaf qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); 421*8dc6d241SJorijn van der Graaf } 422*8dc6d241SJorijn van der Graaf 423*8dc6d241SJorijn van der Graaf static bool qmc6308_volatile_reg(struct device *dev, unsigned int reg) 424*8dc6d241SJorijn van der Graaf { 425*8dc6d241SJorijn van der Graaf return reg >= QMC6308_REG_X_LSB && reg <= QMC6308_REG_STATUS; 426*8dc6d241SJorijn van der Graaf } 427*8dc6d241SJorijn van der Graaf 428*8dc6d241SJorijn van der Graaf static bool qmc6308_writable_reg(struct device *dev, unsigned int reg) 429*8dc6d241SJorijn van der Graaf { 430*8dc6d241SJorijn van der Graaf switch (reg) { 431*8dc6d241SJorijn van der Graaf case QMC6308_REG_CTRL1: 432*8dc6d241SJorijn van der Graaf case QMC6308_REG_CTRL2: 433*8dc6d241SJorijn van der Graaf case QMC6308_REG_CTRL3: 434*8dc6d241SJorijn van der Graaf case QMC6308_REG_CTRL4: 435*8dc6d241SJorijn van der Graaf return true; 436*8dc6d241SJorijn van der Graaf default: 437*8dc6d241SJorijn van der Graaf return false; 438*8dc6d241SJorijn van der Graaf } 439*8dc6d241SJorijn van der Graaf } 440*8dc6d241SJorijn van der Graaf 441*8dc6d241SJorijn van der Graaf static const struct regmap_config qmc6308_regmap_config = { 442*8dc6d241SJorijn van der Graaf .reg_bits = 8, 443*8dc6d241SJorijn van der Graaf .val_bits = 8, 444*8dc6d241SJorijn van der Graaf .max_register = QMC6308_REG_CTRL4, 445*8dc6d241SJorijn van der Graaf .cache_type = REGCACHE_MAPLE, 446*8dc6d241SJorijn van der Graaf .volatile_reg = qmc6308_volatile_reg, 447*8dc6d241SJorijn van der Graaf .writeable_reg = qmc6308_writable_reg, 448*8dc6d241SJorijn van der Graaf }; 449*8dc6d241SJorijn van der Graaf 450*8dc6d241SJorijn van der Graaf #define QMC6308_CHANNEL(_axis) \ 451*8dc6d241SJorijn van der Graaf { \ 452*8dc6d241SJorijn van der Graaf .type = IIO_MAGN, \ 453*8dc6d241SJorijn van der Graaf .modified = 1, \ 454*8dc6d241SJorijn van der Graaf .channel2 = IIO_MOD_##_axis, \ 455*8dc6d241SJorijn van der Graaf .address = QMC6308_AXIS_##_axis, \ 456*8dc6d241SJorijn van der Graaf .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 457*8dc6d241SJorijn van der Graaf .info_mask_shared_by_type = \ 458*8dc6d241SJorijn van der Graaf BIT(IIO_CHAN_INFO_SCALE) | \ 459*8dc6d241SJorijn van der Graaf BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 460*8dc6d241SJorijn van der Graaf BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ 461*8dc6d241SJorijn van der Graaf .info_mask_shared_by_type_available = \ 462*8dc6d241SJorijn van der Graaf BIT(IIO_CHAN_INFO_SCALE) | \ 463*8dc6d241SJorijn van der Graaf BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 464*8dc6d241SJorijn van der Graaf BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ 465*8dc6d241SJorijn van der Graaf .ext_info = qmc6308_ext_info, \ 466*8dc6d241SJorijn van der Graaf } 467*8dc6d241SJorijn van der Graaf 468*8dc6d241SJorijn van der Graaf static const struct iio_chan_spec qmc6308_channels[] = { 469*8dc6d241SJorijn van der Graaf QMC6308_CHANNEL(X), 470*8dc6d241SJorijn van der Graaf QMC6308_CHANNEL(Y), 471*8dc6d241SJorijn van der Graaf QMC6308_CHANNEL(Z), 472*8dc6d241SJorijn van der Graaf }; 473*8dc6d241SJorijn van der Graaf 474*8dc6d241SJorijn van der Graaf static int qmc6308_probe(struct i2c_client *client) 475*8dc6d241SJorijn van der Graaf { 476*8dc6d241SJorijn van der Graaf struct device *dev = &client->dev; 477*8dc6d241SJorijn van der Graaf struct qmc6308_data *data; 478*8dc6d241SJorijn van der Graaf struct iio_dev *indio_dev; 479*8dc6d241SJorijn van der Graaf struct regmap *map; 480*8dc6d241SJorijn van der Graaf int ret; 481*8dc6d241SJorijn van der Graaf 482*8dc6d241SJorijn van der Graaf indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 483*8dc6d241SJorijn van der Graaf if (!indio_dev) 484*8dc6d241SJorijn van der Graaf return -ENOMEM; 485*8dc6d241SJorijn van der Graaf 486*8dc6d241SJorijn van der Graaf i2c_set_clientdata(client, indio_dev); 487*8dc6d241SJorijn van der Graaf 488*8dc6d241SJorijn van der Graaf map = devm_regmap_init_i2c(client, &qmc6308_regmap_config); 489*8dc6d241SJorijn van der Graaf if (IS_ERR(map)) 490*8dc6d241SJorijn van der Graaf return dev_err_probe(dev, PTR_ERR(map), 491*8dc6d241SJorijn van der Graaf "regmap initialization failed\n"); 492*8dc6d241SJorijn van der Graaf 493*8dc6d241SJorijn van der Graaf ret = devm_regulator_get_enable(dev, "vdd"); 494*8dc6d241SJorijn van der Graaf if (ret) 495*8dc6d241SJorijn van der Graaf return dev_err_probe(dev, ret, 496*8dc6d241SJorijn van der Graaf "Failed to enable VDD regulator\n"); 497*8dc6d241SJorijn van der Graaf 498*8dc6d241SJorijn van der Graaf fsleep(QMC6308_POR_US); 499*8dc6d241SJorijn van der Graaf 500*8dc6d241SJorijn van der Graaf data = iio_priv(indio_dev); 501*8dc6d241SJorijn van der Graaf data->regmap = map; 502*8dc6d241SJorijn van der Graaf 503*8dc6d241SJorijn van der Graaf ret = devm_mutex_init(dev, &data->mutex); 504*8dc6d241SJorijn van der Graaf if (ret) 505*8dc6d241SJorijn van der Graaf return ret; 506*8dc6d241SJorijn van der Graaf 507*8dc6d241SJorijn van der Graaf ret = iio_read_mount_matrix(dev, &data->orientation); 508*8dc6d241SJorijn van der Graaf if (ret) 509*8dc6d241SJorijn van der Graaf return dev_err_probe(dev, ret, 510*8dc6d241SJorijn van der Graaf "Failed to read mount matrix\n"); 511*8dc6d241SJorijn van der Graaf 512*8dc6d241SJorijn van der Graaf indio_dev->name = "qmc6308"; 513*8dc6d241SJorijn van der Graaf indio_dev->info = &qmc6308_info; 514*8dc6d241SJorijn van der Graaf indio_dev->channels = qmc6308_channels; 515*8dc6d241SJorijn van der Graaf indio_dev->num_channels = ARRAY_SIZE(qmc6308_channels); 516*8dc6d241SJorijn van der Graaf indio_dev->modes = INDIO_DIRECT_MODE; 517*8dc6d241SJorijn van der Graaf 518*8dc6d241SJorijn van der Graaf ret = qmc6308_init(data); 519*8dc6d241SJorijn van der Graaf if (ret) 520*8dc6d241SJorijn van der Graaf return dev_err_probe(dev, ret, "qmc6308 init failed\n"); 521*8dc6d241SJorijn van der Graaf 522*8dc6d241SJorijn van der Graaf ret = pm_runtime_set_active(dev); 523*8dc6d241SJorijn van der Graaf if (ret) 524*8dc6d241SJorijn van der Graaf return ret; 525*8dc6d241SJorijn van der Graaf 526*8dc6d241SJorijn van der Graaf ret = devm_add_action_or_reset(dev, qmc6308_power_down_action, data); 527*8dc6d241SJorijn van der Graaf if (ret) 528*8dc6d241SJorijn van der Graaf return ret; 529*8dc6d241SJorijn van der Graaf 530*8dc6d241SJorijn van der Graaf pm_runtime_use_autosuspend(dev); 531*8dc6d241SJorijn van der Graaf pm_runtime_set_autosuspend_delay(dev, QMC6308_AUTOSUSPEND_DELAY_MS); 532*8dc6d241SJorijn van der Graaf 533*8dc6d241SJorijn van der Graaf ret = devm_pm_runtime_enable(dev); 534*8dc6d241SJorijn van der Graaf if (ret) 535*8dc6d241SJorijn van der Graaf return ret; 536*8dc6d241SJorijn van der Graaf 537*8dc6d241SJorijn van der Graaf return devm_iio_device_register(dev, indio_dev); 538*8dc6d241SJorijn van der Graaf } 539*8dc6d241SJorijn van der Graaf 540*8dc6d241SJorijn van der Graaf static int qmc6308_runtime_suspend(struct device *dev) 541*8dc6d241SJorijn van der Graaf { 542*8dc6d241SJorijn van der Graaf struct iio_dev *indio_dev = dev_get_drvdata(dev); 543*8dc6d241SJorijn van der Graaf struct qmc6308_data *data = iio_priv(indio_dev); 544*8dc6d241SJorijn van der Graaf 545*8dc6d241SJorijn van der Graaf return qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); 546*8dc6d241SJorijn van der Graaf } 547*8dc6d241SJorijn van der Graaf 548*8dc6d241SJorijn van der Graaf static int qmc6308_runtime_resume(struct device *dev) 549*8dc6d241SJorijn van der Graaf { 550*8dc6d241SJorijn van der Graaf struct iio_dev *indio_dev = dev_get_drvdata(dev); 551*8dc6d241SJorijn van der Graaf struct qmc6308_data *data = iio_priv(indio_dev); 552*8dc6d241SJorijn van der Graaf unsigned int status; 553*8dc6d241SJorijn van der Graaf int ret; 554*8dc6d241SJorijn van der Graaf 555*8dc6d241SJorijn van der Graaf ret = qmc6308_set_mode(data, QMC6308_MODE_NORMAL); 556*8dc6d241SJorijn van der Graaf if (ret) 557*8dc6d241SJorijn van der Graaf return ret; 558*8dc6d241SJorijn van der Graaf 559*8dc6d241SJorijn van der Graaf /* 560*8dc6d241SJorijn van der Graaf * DRDY may still be set for a sample converted before the last 561*8dc6d241SJorijn van der Graaf * suspend; reading the status register clears it so the next 562*8dc6d241SJorijn van der Graaf * measurement waits for fresh data. 563*8dc6d241SJorijn van der Graaf */ 564*8dc6d241SJorijn van der Graaf ret = regmap_read(data->regmap, QMC6308_REG_STATUS, &status); 565*8dc6d241SJorijn van der Graaf if (ret) { 566*8dc6d241SJorijn van der Graaf /* Best effort to leave the chip in a consistent state */ 567*8dc6d241SJorijn van der Graaf qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); 568*8dc6d241SJorijn van der Graaf } 569*8dc6d241SJorijn van der Graaf 570*8dc6d241SJorijn van der Graaf return ret; 571*8dc6d241SJorijn van der Graaf } 572*8dc6d241SJorijn van der Graaf 573*8dc6d241SJorijn van der Graaf static DEFINE_RUNTIME_DEV_PM_OPS(qmc6308_pm_ops, qmc6308_runtime_suspend, 574*8dc6d241SJorijn van der Graaf qmc6308_runtime_resume, NULL); 575*8dc6d241SJorijn van der Graaf 576*8dc6d241SJorijn van der Graaf static const struct of_device_id qmc6308_match[] = { 577*8dc6d241SJorijn van der Graaf { .compatible = "qstcorp,qmc6308" }, 578*8dc6d241SJorijn van der Graaf { } 579*8dc6d241SJorijn van der Graaf }; 580*8dc6d241SJorijn van der Graaf MODULE_DEVICE_TABLE(of, qmc6308_match); 581*8dc6d241SJorijn van der Graaf 582*8dc6d241SJorijn van der Graaf static const struct i2c_device_id qmc6308_id[] = { 583*8dc6d241SJorijn van der Graaf { .name = "qmc6308" }, 584*8dc6d241SJorijn van der Graaf { } 585*8dc6d241SJorijn van der Graaf }; 586*8dc6d241SJorijn van der Graaf MODULE_DEVICE_TABLE(i2c, qmc6308_id); 587*8dc6d241SJorijn van der Graaf 588*8dc6d241SJorijn van der Graaf static struct i2c_driver qmc6308_driver = { 589*8dc6d241SJorijn van der Graaf .driver = { 590*8dc6d241SJorijn van der Graaf .name = "qmc6308", 591*8dc6d241SJorijn van der Graaf .of_match_table = qmc6308_match, 592*8dc6d241SJorijn van der Graaf .pm = pm_ptr(&qmc6308_pm_ops), 593*8dc6d241SJorijn van der Graaf }, 594*8dc6d241SJorijn van der Graaf .id_table = qmc6308_id, 595*8dc6d241SJorijn van der Graaf .probe = qmc6308_probe, 596*8dc6d241SJorijn van der Graaf }; 597*8dc6d241SJorijn van der Graaf module_i2c_driver(qmc6308_driver); 598*8dc6d241SJorijn van der Graaf 599*8dc6d241SJorijn van der Graaf MODULE_DESCRIPTION("QST QMC6308 3-Axis Magnetic Sensor driver"); 600*8dc6d241SJorijn van der Graaf MODULE_AUTHOR("Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>"); 601*8dc6d241SJorijn van der Graaf MODULE_LICENSE("GPL"); 602