xref: /linux/drivers/iio/magnetometer/qmc6308.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
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, &reg);
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