xref: /openbmc/linux/drivers/iio/magnetometer/ak8975.c (revision fac59652993f075d57860769c99045b3ca18780d)
116216333SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
22fc72cd8SJonathan Cameron /*
32fc72cd8SJonathan Cameron  * A sensor driver for the magnetometer AK8975.
42fc72cd8SJonathan Cameron  *
52fc72cd8SJonathan Cameron  * Magnetic compass sensor driver for monitoring magnetic flux information.
62fc72cd8SJonathan Cameron  *
72fc72cd8SJonathan Cameron  * Copyright (c) 2010, NVIDIA Corporation.
82fc72cd8SJonathan Cameron  */
92fc72cd8SJonathan Cameron 
102fc72cd8SJonathan Cameron #include <linux/module.h>
118e5a0426SJonathan Cameron #include <linux/mod_devicetable.h>
122fc72cd8SJonathan Cameron #include <linux/kernel.h>
132fc72cd8SJonathan Cameron #include <linux/slab.h>
142fc72cd8SJonathan Cameron #include <linux/i2c.h>
1594a6d5cfSJacek Anaszewski #include <linux/interrupt.h>
162fc72cd8SJonathan Cameron #include <linux/err.h>
172fc72cd8SJonathan Cameron #include <linux/mutex.h>
182fc72cd8SJonathan Cameron #include <linux/delay.h>
1994a6d5cfSJacek Anaszewski #include <linux/bitops.h>
202c289e63SLinus Walleij #include <linux/gpio/consumer.h>
2163d5d525SGregor Boirie #include <linux/regulator/consumer.h>
22cde4cb5dSLinus Walleij #include <linux/pm_runtime.h>
232fc72cd8SJonathan Cameron 
242fc72cd8SJonathan Cameron #include <linux/iio/iio.h>
252fc72cd8SJonathan Cameron #include <linux/iio/sysfs.h>
26bc11ca4aSGregor Boirie #include <linux/iio/buffer.h>
27bc11ca4aSGregor Boirie #include <linux/iio/trigger.h>
28bc11ca4aSGregor Boirie #include <linux/iio/trigger_consumer.h>
29bc11ca4aSGregor Boirie #include <linux/iio/triggered_buffer.h>
3097eacb91SGregor Boirie 
312fc72cd8SJonathan Cameron /*
322fc72cd8SJonathan Cameron  * Register definitions, as well as various shifts and masks to get at the
332fc72cd8SJonathan Cameron  * individual fields of the registers.
342fc72cd8SJonathan Cameron  */
352fc72cd8SJonathan Cameron #define AK8975_REG_WIA			0x00
362fc72cd8SJonathan Cameron #define AK8975_DEVICE_ID		0x48
372fc72cd8SJonathan Cameron 
382fc72cd8SJonathan Cameron #define AK8975_REG_INFO			0x01
392fc72cd8SJonathan Cameron 
402fc72cd8SJonathan Cameron #define AK8975_REG_ST1			0x02
412fc72cd8SJonathan Cameron #define AK8975_REG_ST1_DRDY_SHIFT	0
422fc72cd8SJonathan Cameron #define AK8975_REG_ST1_DRDY_MASK	(1 << AK8975_REG_ST1_DRDY_SHIFT)
432fc72cd8SJonathan Cameron 
442fc72cd8SJonathan Cameron #define AK8975_REG_HXL			0x03
452fc72cd8SJonathan Cameron #define AK8975_REG_HXH			0x04
462fc72cd8SJonathan Cameron #define AK8975_REG_HYL			0x05
472fc72cd8SJonathan Cameron #define AK8975_REG_HYH			0x06
482fc72cd8SJonathan Cameron #define AK8975_REG_HZL			0x07
492fc72cd8SJonathan Cameron #define AK8975_REG_HZH			0x08
502fc72cd8SJonathan Cameron #define AK8975_REG_ST2			0x09
512fc72cd8SJonathan Cameron #define AK8975_REG_ST2_DERR_SHIFT	2
522fc72cd8SJonathan Cameron #define AK8975_REG_ST2_DERR_MASK	(1 << AK8975_REG_ST2_DERR_SHIFT)
532fc72cd8SJonathan Cameron 
542fc72cd8SJonathan Cameron #define AK8975_REG_ST2_HOFL_SHIFT	3
552fc72cd8SJonathan Cameron #define AK8975_REG_ST2_HOFL_MASK	(1 << AK8975_REG_ST2_HOFL_SHIFT)
562fc72cd8SJonathan Cameron 
572fc72cd8SJonathan Cameron #define AK8975_REG_CNTL			0x0A
582fc72cd8SJonathan Cameron #define AK8975_REG_CNTL_MODE_SHIFT	0
592fc72cd8SJonathan Cameron #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
6071222bf5SGwendal Grignou #define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
6171222bf5SGwendal Grignou #define AK8975_REG_CNTL_MODE_ONCE	0x01
6271222bf5SGwendal Grignou #define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
6371222bf5SGwendal Grignou #define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
642fc72cd8SJonathan Cameron 
652fc72cd8SJonathan Cameron #define AK8975_REG_RSVC			0x0B
662fc72cd8SJonathan Cameron #define AK8975_REG_ASTC			0x0C
672fc72cd8SJonathan Cameron #define AK8975_REG_TS1			0x0D
682fc72cd8SJonathan Cameron #define AK8975_REG_TS2			0x0E
692fc72cd8SJonathan Cameron #define AK8975_REG_I2CDIS		0x0F
702fc72cd8SJonathan Cameron #define AK8975_REG_ASAX			0x10
712fc72cd8SJonathan Cameron #define AK8975_REG_ASAY			0x11
722fc72cd8SJonathan Cameron #define AK8975_REG_ASAZ			0x12
732fc72cd8SJonathan Cameron 
742fc72cd8SJonathan Cameron #define AK8975_MAX_REGS			AK8975_REG_ASAZ
752fc72cd8SJonathan Cameron 
762fc72cd8SJonathan Cameron /*
7757e73a42SGwendal Grignou  * AK09912 Register definitions
7857e73a42SGwendal Grignou  */
7957e73a42SGwendal Grignou #define AK09912_REG_WIA1		0x00
8057e73a42SGwendal Grignou #define AK09912_REG_WIA2		0x01
8176e28aa9SMatt Ranostay #define AK09916_DEVICE_ID		0x09
8257e73a42SGwendal Grignou #define AK09912_DEVICE_ID		0x04
8357e73a42SGwendal Grignou #define AK09911_DEVICE_ID		0x05
8457e73a42SGwendal Grignou 
8557e73a42SGwendal Grignou #define AK09911_REG_INFO1		0x02
8657e73a42SGwendal Grignou #define AK09911_REG_INFO2		0x03
8757e73a42SGwendal Grignou 
8857e73a42SGwendal Grignou #define AK09912_REG_ST1			0x10
8957e73a42SGwendal Grignou 
9057e73a42SGwendal Grignou #define AK09912_REG_ST1_DRDY_SHIFT	0
9157e73a42SGwendal Grignou #define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
9257e73a42SGwendal Grignou 
9357e73a42SGwendal Grignou #define AK09912_REG_HXL			0x11
9457e73a42SGwendal Grignou #define AK09912_REG_HXH			0x12
9557e73a42SGwendal Grignou #define AK09912_REG_HYL			0x13
9657e73a42SGwendal Grignou #define AK09912_REG_HYH			0x14
9757e73a42SGwendal Grignou #define AK09912_REG_HZL			0x15
9857e73a42SGwendal Grignou #define AK09912_REG_HZH			0x16
9957e73a42SGwendal Grignou #define AK09912_REG_TMPS		0x17
10057e73a42SGwendal Grignou 
10157e73a42SGwendal Grignou #define AK09912_REG_ST2			0x18
10257e73a42SGwendal Grignou #define AK09912_REG_ST2_HOFL_SHIFT	3
10357e73a42SGwendal Grignou #define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
10457e73a42SGwendal Grignou 
10557e73a42SGwendal Grignou #define AK09912_REG_CNTL1		0x30
10657e73a42SGwendal Grignou 
10757e73a42SGwendal Grignou #define AK09912_REG_CNTL2		0x31
10857e73a42SGwendal Grignou #define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
10957e73a42SGwendal Grignou #define AK09912_REG_CNTL_MODE_ONCE	0x01
11057e73a42SGwendal Grignou #define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
11157e73a42SGwendal Grignou #define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
11257e73a42SGwendal Grignou #define AK09912_REG_CNTL2_MODE_SHIFT	0
11357e73a42SGwendal Grignou #define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
11457e73a42SGwendal Grignou 
11557e73a42SGwendal Grignou #define AK09912_REG_CNTL3		0x32
11657e73a42SGwendal Grignou 
11757e73a42SGwendal Grignou #define AK09912_REG_TS1			0x33
11857e73a42SGwendal Grignou #define AK09912_REG_TS2			0x34
11957e73a42SGwendal Grignou #define AK09912_REG_TS3			0x35
12057e73a42SGwendal Grignou #define AK09912_REG_I2CDIS		0x36
12157e73a42SGwendal Grignou #define AK09912_REG_TS4			0x37
12257e73a42SGwendal Grignou 
12357e73a42SGwendal Grignou #define AK09912_REG_ASAX		0x60
12457e73a42SGwendal Grignou #define AK09912_REG_ASAY		0x61
12557e73a42SGwendal Grignou #define AK09912_REG_ASAZ		0x62
12657e73a42SGwendal Grignou 
12757e73a42SGwendal Grignou #define AK09912_MAX_REGS		AK09912_REG_ASAZ
12857e73a42SGwendal Grignou 
12957e73a42SGwendal Grignou /*
1302fc72cd8SJonathan Cameron  * Miscellaneous values.
1312fc72cd8SJonathan Cameron  */
1322fc72cd8SJonathan Cameron #define AK8975_MAX_CONVERSION_TIMEOUT	500
1332fc72cd8SJonathan Cameron #define AK8975_CONVERSION_DONE_POLL_TIME 10
13494a6d5cfSJacek Anaszewski #define AK8975_DATA_READY_TIMEOUT	((100*HZ)/1000)
135286f74c2SGwendal Grignou 
136286f74c2SGwendal Grignou /*
137286f74c2SGwendal Grignou  * Precalculate scale factor (in Gauss units) for each axis and
138286f74c2SGwendal Grignou  * store in the device data.
139286f74c2SGwendal Grignou  *
140286f74c2SGwendal Grignou  * This scale factor is axis-dependent, and is derived from 3 calibration
141286f74c2SGwendal Grignou  * factors ASA(x), ASA(y), and ASA(z).
142286f74c2SGwendal Grignou  *
143286f74c2SGwendal Grignou  * These ASA values are read from the sensor device at start of day, and
144286f74c2SGwendal Grignou  * cached in the device context struct.
145286f74c2SGwendal Grignou  *
146286f74c2SGwendal Grignou  * Adjusting the flux value with the sensitivity adjustment value should be
147286f74c2SGwendal Grignou  * done via the following formula:
148286f74c2SGwendal Grignou  *
149286f74c2SGwendal Grignou  * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
150286f74c2SGwendal Grignou  * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
151286f74c2SGwendal Grignou  * is the resultant adjusted value.
152286f74c2SGwendal Grignou  *
153286f74c2SGwendal Grignou  * We reduce the formula to:
154286f74c2SGwendal Grignou  *
155286f74c2SGwendal Grignou  * Hadj = H * (ASA + 128) / 256
156286f74c2SGwendal Grignou  *
157286f74c2SGwendal Grignou  * H is in the range of -4096 to 4095.  The magnetometer has a range of
158286f74c2SGwendal Grignou  * +-1229uT.  To go from the raw value to uT is:
159286f74c2SGwendal Grignou  *
160286f74c2SGwendal Grignou  * HuT = H * 1229/4096, or roughly, 3/10.
161286f74c2SGwendal Grignou  *
162286f74c2SGwendal Grignou  * Since 1uT = 0.01 gauss, our final scale factor becomes:
163286f74c2SGwendal Grignou  *
164286f74c2SGwendal Grignou  * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
165286f74c2SGwendal Grignou  * Hadj = H * ((ASA + 128) * 0.003) / 256
166286f74c2SGwendal Grignou  *
167286f74c2SGwendal Grignou  * Since ASA doesn't change, we cache the resultant scale factor into the
168286f74c2SGwendal Grignou  * device context in ak8975_setup().
169286f74c2SGwendal Grignou  *
170286f74c2SGwendal Grignou  * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
171286f74c2SGwendal Grignou  * multiply the stored scale value by 1e6.
172286f74c2SGwendal Grignou  */
ak8975_raw_to_gauss(u16 data)173286f74c2SGwendal Grignou static long ak8975_raw_to_gauss(u16 data)
174286f74c2SGwendal Grignou {
175286f74c2SGwendal Grignou 	return (((long)data + 128) * 3000) / 256;
176286f74c2SGwendal Grignou }
177286f74c2SGwendal Grignou 
178286f74c2SGwendal Grignou /*
17957e73a42SGwendal Grignou  * For AK8963 and AK09911, same calculation, but the device is less sensitive:
180286f74c2SGwendal Grignou  *
181286f74c2SGwendal Grignou  * H is in the range of +-8190.  The magnetometer has a range of
182286f74c2SGwendal Grignou  * +-4912uT.  To go from the raw value to uT is:
183286f74c2SGwendal Grignou  *
184286f74c2SGwendal Grignou  * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
185286f74c2SGwendal Grignou  */
18657e73a42SGwendal Grignou 
ak8963_09911_raw_to_gauss(u16 data)18757e73a42SGwendal Grignou static long ak8963_09911_raw_to_gauss(u16 data)
188286f74c2SGwendal Grignou {
189286f74c2SGwendal Grignou 	return (((long)data + 128) * 6000) / 256;
190286f74c2SGwendal Grignou }
1916027c077SSrinivas Pandruvada 
19257e73a42SGwendal Grignou /*
19357e73a42SGwendal Grignou  * For AK09912, same calculation, except the device is more sensitive:
19457e73a42SGwendal Grignou  *
19557e73a42SGwendal Grignou  * H is in the range of -32752 to 32752.  The magnetometer has a range of
19657e73a42SGwendal Grignou  * +-4912uT.  To go from the raw value to uT is:
19757e73a42SGwendal Grignou  *
19857e73a42SGwendal Grignou  * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
19957e73a42SGwendal Grignou  */
ak09912_raw_to_gauss(u16 data)20057e73a42SGwendal Grignou static long ak09912_raw_to_gauss(u16 data)
20157e73a42SGwendal Grignou {
20257e73a42SGwendal Grignou 	return (((long)data + 128) * 1500) / 256;
20357e73a42SGwendal Grignou }
20457e73a42SGwendal Grignou 
2056027c077SSrinivas Pandruvada /* Compatible Asahi Kasei Compass parts */
2066027c077SSrinivas Pandruvada enum asahi_compass_chipset {
2076027c077SSrinivas Pandruvada 	AK8975,
2086027c077SSrinivas Pandruvada 	AK8963,
20957e73a42SGwendal Grignou 	AK09911,
21057e73a42SGwendal Grignou 	AK09912,
21176e28aa9SMatt Ranostay 	AK09916,
212286f74c2SGwendal Grignou };
213286f74c2SGwendal Grignou 
214286f74c2SGwendal Grignou enum ak_ctrl_reg_addr {
215286f74c2SGwendal Grignou 	ST1,
216286f74c2SGwendal Grignou 	ST2,
217286f74c2SGwendal Grignou 	CNTL,
218286f74c2SGwendal Grignou 	ASA_BASE,
219286f74c2SGwendal Grignou 	MAX_REGS,
220286f74c2SGwendal Grignou 	REGS_END,
221286f74c2SGwendal Grignou };
222286f74c2SGwendal Grignou 
223286f74c2SGwendal Grignou enum ak_ctrl_reg_mask {
224286f74c2SGwendal Grignou 	ST1_DRDY,
225286f74c2SGwendal Grignou 	ST2_HOFL,
226286f74c2SGwendal Grignou 	ST2_DERR,
227286f74c2SGwendal Grignou 	CNTL_MODE,
228286f74c2SGwendal Grignou 	MASK_END,
229286f74c2SGwendal Grignou };
230286f74c2SGwendal Grignou 
231286f74c2SGwendal Grignou enum ak_ctrl_mode {
232286f74c2SGwendal Grignou 	POWER_DOWN,
233286f74c2SGwendal Grignou 	MODE_ONCE,
234286f74c2SGwendal Grignou 	SELF_TEST,
235286f74c2SGwendal Grignou 	FUSE_ROM,
236286f74c2SGwendal Grignou 	MODE_END,
237286f74c2SGwendal Grignou };
238286f74c2SGwendal Grignou 
239286f74c2SGwendal Grignou struct ak_def {
240286f74c2SGwendal Grignou 	enum asahi_compass_chipset type;
241286f74c2SGwendal Grignou 	long (*raw_to_gauss)(u16 data);
242286f74c2SGwendal Grignou 	u16 range;
243286f74c2SGwendal Grignou 	u8 ctrl_regs[REGS_END];
244286f74c2SGwendal Grignou 	u8 ctrl_masks[MASK_END];
245286f74c2SGwendal Grignou 	u8 ctrl_modes[MODE_END];
246286f74c2SGwendal Grignou 	u8 data_regs[3];
247286f74c2SGwendal Grignou };
248286f74c2SGwendal Grignou 
24971f221f8SAndy Shevchenko static const struct ak_def ak_def_array[] = {
25072a3aef9SAndré Apitzsch 	[AK8975] = {
251286f74c2SGwendal Grignou 		.type = AK8975,
252286f74c2SGwendal Grignou 		.raw_to_gauss = ak8975_raw_to_gauss,
253286f74c2SGwendal Grignou 		.range = 4096,
254286f74c2SGwendal Grignou 		.ctrl_regs = {
255286f74c2SGwendal Grignou 			AK8975_REG_ST1,
256286f74c2SGwendal Grignou 			AK8975_REG_ST2,
257286f74c2SGwendal Grignou 			AK8975_REG_CNTL,
258286f74c2SGwendal Grignou 			AK8975_REG_ASAX,
259286f74c2SGwendal Grignou 			AK8975_MAX_REGS},
260286f74c2SGwendal Grignou 		.ctrl_masks = {
261286f74c2SGwendal Grignou 			AK8975_REG_ST1_DRDY_MASK,
262286f74c2SGwendal Grignou 			AK8975_REG_ST2_HOFL_MASK,
263286f74c2SGwendal Grignou 			AK8975_REG_ST2_DERR_MASK,
264286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_MASK},
265286f74c2SGwendal Grignou 		.ctrl_modes = {
266286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_POWER_DOWN,
267286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_ONCE,
268286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_SELF_TEST,
269286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_FUSE_ROM},
270286f74c2SGwendal Grignou 		.data_regs = {
271286f74c2SGwendal Grignou 			AK8975_REG_HXL,
272286f74c2SGwendal Grignou 			AK8975_REG_HYL,
273286f74c2SGwendal Grignou 			AK8975_REG_HZL},
274286f74c2SGwendal Grignou 	},
27572a3aef9SAndré Apitzsch 	[AK8963] = {
276286f74c2SGwendal Grignou 		.type = AK8963,
27757e73a42SGwendal Grignou 		.raw_to_gauss = ak8963_09911_raw_to_gauss,
278286f74c2SGwendal Grignou 		.range = 8190,
279286f74c2SGwendal Grignou 		.ctrl_regs = {
280286f74c2SGwendal Grignou 			AK8975_REG_ST1,
281286f74c2SGwendal Grignou 			AK8975_REG_ST2,
282286f74c2SGwendal Grignou 			AK8975_REG_CNTL,
283286f74c2SGwendal Grignou 			AK8975_REG_ASAX,
284286f74c2SGwendal Grignou 			AK8975_MAX_REGS},
285286f74c2SGwendal Grignou 		.ctrl_masks = {
286286f74c2SGwendal Grignou 			AK8975_REG_ST1_DRDY_MASK,
287286f74c2SGwendal Grignou 			AK8975_REG_ST2_HOFL_MASK,
288286f74c2SGwendal Grignou 			0,
289286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_MASK},
290286f74c2SGwendal Grignou 		.ctrl_modes = {
291286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_POWER_DOWN,
292286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_ONCE,
293286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_SELF_TEST,
294286f74c2SGwendal Grignou 			AK8975_REG_CNTL_MODE_FUSE_ROM},
295286f74c2SGwendal Grignou 		.data_regs = {
296286f74c2SGwendal Grignou 			AK8975_REG_HXL,
297286f74c2SGwendal Grignou 			AK8975_REG_HYL,
298286f74c2SGwendal Grignou 			AK8975_REG_HZL},
299286f74c2SGwendal Grignou 	},
30072a3aef9SAndré Apitzsch 	[AK09911] = {
30157e73a42SGwendal Grignou 		.type = AK09911,
30257e73a42SGwendal Grignou 		.raw_to_gauss = ak8963_09911_raw_to_gauss,
30357e73a42SGwendal Grignou 		.range = 8192,
30457e73a42SGwendal Grignou 		.ctrl_regs = {
30557e73a42SGwendal Grignou 			AK09912_REG_ST1,
30657e73a42SGwendal Grignou 			AK09912_REG_ST2,
30757e73a42SGwendal Grignou 			AK09912_REG_CNTL2,
30857e73a42SGwendal Grignou 			AK09912_REG_ASAX,
30957e73a42SGwendal Grignou 			AK09912_MAX_REGS},
31057e73a42SGwendal Grignou 		.ctrl_masks = {
31157e73a42SGwendal Grignou 			AK09912_REG_ST1_DRDY_MASK,
31257e73a42SGwendal Grignou 			AK09912_REG_ST2_HOFL_MASK,
31357e73a42SGwendal Grignou 			0,
31457e73a42SGwendal Grignou 			AK09912_REG_CNTL2_MODE_MASK},
31557e73a42SGwendal Grignou 		.ctrl_modes = {
31657e73a42SGwendal Grignou 			AK09912_REG_CNTL_MODE_POWER_DOWN,
31757e73a42SGwendal Grignou 			AK09912_REG_CNTL_MODE_ONCE,
31857e73a42SGwendal Grignou 			AK09912_REG_CNTL_MODE_SELF_TEST,
31957e73a42SGwendal Grignou 			AK09912_REG_CNTL_MODE_FUSE_ROM},
32057e73a42SGwendal Grignou 		.data_regs = {
32157e73a42SGwendal Grignou 			AK09912_REG_HXL,
32257e73a42SGwendal Grignou 			AK09912_REG_HYL,
32357e73a42SGwendal Grignou 			AK09912_REG_HZL},
32457e73a42SGwendal Grignou 	},
32572a3aef9SAndré Apitzsch 	[AK09912] = {
32657e73a42SGwendal Grignou 		.type = AK09912,
32757e73a42SGwendal Grignou 		.raw_to_gauss = ak09912_raw_to_gauss,
32857e73a42SGwendal Grignou 		.range = 32752,
32957e73a42SGwendal Grignou 		.ctrl_regs = {
33057e73a42SGwendal Grignou 			AK09912_REG_ST1,
33157e73a42SGwendal Grignou 			AK09912_REG_ST2,
33257e73a42SGwendal Grignou 			AK09912_REG_CNTL2,
33357e73a42SGwendal Grignou 			AK09912_REG_ASAX,
33457e73a42SGwendal Grignou 			AK09912_MAX_REGS},
33557e73a42SGwendal Grignou 		.ctrl_masks = {
33657e73a42SGwendal Grignou 			AK09912_REG_ST1_DRDY_MASK,
33757e73a42SGwendal Grignou 			AK09912_REG_ST2_HOFL_MASK,
33857e73a42SGwendal Grignou 			0,
33957e73a42SGwendal Grignou 			AK09912_REG_CNTL2_MODE_MASK},
34057e73a42SGwendal Grignou 		.ctrl_modes = {
34157e73a42SGwendal Grignou 			AK09912_REG_CNTL_MODE_POWER_DOWN,
34257e73a42SGwendal Grignou 			AK09912_REG_CNTL_MODE_ONCE,
34357e73a42SGwendal Grignou 			AK09912_REG_CNTL_MODE_SELF_TEST,
34457e73a42SGwendal Grignou 			AK09912_REG_CNTL_MODE_FUSE_ROM},
34557e73a42SGwendal Grignou 		.data_regs = {
34657e73a42SGwendal Grignou 			AK09912_REG_HXL,
34757e73a42SGwendal Grignou 			AK09912_REG_HYL,
34857e73a42SGwendal Grignou 			AK09912_REG_HZL},
34976e28aa9SMatt Ranostay 	},
35072a3aef9SAndré Apitzsch 	[AK09916] = {
35176e28aa9SMatt Ranostay 		.type = AK09916,
35276e28aa9SMatt Ranostay 		.raw_to_gauss = ak09912_raw_to_gauss,
35376e28aa9SMatt Ranostay 		.range = 32752,
35476e28aa9SMatt Ranostay 		.ctrl_regs = {
35576e28aa9SMatt Ranostay 			AK09912_REG_ST1,
35676e28aa9SMatt Ranostay 			AK09912_REG_ST2,
35776e28aa9SMatt Ranostay 			AK09912_REG_CNTL2,
35876e28aa9SMatt Ranostay 			AK09912_REG_ASAX,
35976e28aa9SMatt Ranostay 			AK09912_MAX_REGS},
36076e28aa9SMatt Ranostay 		.ctrl_masks = {
36176e28aa9SMatt Ranostay 			AK09912_REG_ST1_DRDY_MASK,
36276e28aa9SMatt Ranostay 			AK09912_REG_ST2_HOFL_MASK,
36376e28aa9SMatt Ranostay 			0,
36476e28aa9SMatt Ranostay 			AK09912_REG_CNTL2_MODE_MASK},
36576e28aa9SMatt Ranostay 		.ctrl_modes = {
36676e28aa9SMatt Ranostay 			AK09912_REG_CNTL_MODE_POWER_DOWN,
36776e28aa9SMatt Ranostay 			AK09912_REG_CNTL_MODE_ONCE,
36876e28aa9SMatt Ranostay 			AK09912_REG_CNTL_MODE_SELF_TEST,
36976e28aa9SMatt Ranostay 			AK09912_REG_CNTL_MODE_FUSE_ROM},
37076e28aa9SMatt Ranostay 		.data_regs = {
37176e28aa9SMatt Ranostay 			AK09912_REG_HXL,
37276e28aa9SMatt Ranostay 			AK09912_REG_HYL,
37376e28aa9SMatt Ranostay 			AK09912_REG_HZL},
37457e73a42SGwendal Grignou 	}
3756027c077SSrinivas Pandruvada };
3762fc72cd8SJonathan Cameron 
3772fc72cd8SJonathan Cameron /*
3782fc72cd8SJonathan Cameron  * Per-instance context data for the device.
3792fc72cd8SJonathan Cameron  */
3802fc72cd8SJonathan Cameron struct ak8975_data {
3812fc72cd8SJonathan Cameron 	struct i2c_client	*client;
382f78c5f96SJulia Lawall 	const struct ak_def	*def;
3832fc72cd8SJonathan Cameron 	struct mutex		lock;
3842fc72cd8SJonathan Cameron 	u8			asa[3];
3852fc72cd8SJonathan Cameron 	long			raw_to_gauss[3];
3862c289e63SLinus Walleij 	struct gpio_desc	*eoc_gpiod;
3879604ed75SJonathan Albrieux 	struct gpio_desc	*reset_gpiod;
38894a6d5cfSJacek Anaszewski 	int			eoc_irq;
38994a6d5cfSJacek Anaszewski 	wait_queue_head_t	data_ready_queue;
39094a6d5cfSJacek Anaszewski 	unsigned long		flags;
391286f74c2SGwendal Grignou 	u8			cntl_cache;
39297eacb91SGregor Boirie 	struct iio_mount_matrix orientation;
393a9b72c90SGregor Boirie 	struct regulator	*vdd;
394b21d3f34SLinus Walleij 	struct regulator	*vid;
39502ad21ceSJonathan Cameron 
39602ad21ceSJonathan Cameron 	/* Ensure natural alignment of timestamp */
39702ad21ceSJonathan Cameron 	struct {
39802ad21ceSJonathan Cameron 		s16 channels[3];
39902ad21ceSJonathan Cameron 		s64 ts __aligned(8);
40002ad21ceSJonathan Cameron 	} scan;
4012fc72cd8SJonathan Cameron };
4022fc72cd8SJonathan Cameron 
403a9b72c90SGregor Boirie /* Enable attached power regulator if any. */
ak8975_power_on(const struct ak8975_data * data)4049e6c16d9SLinus Walleij static int ak8975_power_on(const struct ak8975_data *data)
405a9b72c90SGregor Boirie {
406a9b72c90SGregor Boirie 	int ret;
407a9b72c90SGregor Boirie 
408a9b72c90SGregor Boirie 	ret = regulator_enable(data->vdd);
40990e96fddSLinus Walleij 	if (ret) {
4109e6c16d9SLinus Walleij 		dev_warn(&data->client->dev,
41190e96fddSLinus Walleij 			 "Failed to enable specified Vdd supply\n");
412a9b72c90SGregor Boirie 		return ret;
413a9b72c90SGregor Boirie 	}
414b21d3f34SLinus Walleij 	ret = regulator_enable(data->vid);
415b21d3f34SLinus Walleij 	if (ret) {
4169e6c16d9SLinus Walleij 		dev_warn(&data->client->dev,
417b21d3f34SLinus Walleij 			 "Failed to enable specified Vid supply\n");
4183a26787dSZheyu Ma 		regulator_disable(data->vdd);
419b21d3f34SLinus Walleij 		return ret;
420b21d3f34SLinus Walleij 	}
4219604ed75SJonathan Albrieux 
4229604ed75SJonathan Albrieux 	gpiod_set_value_cansleep(data->reset_gpiod, 0);
4239604ed75SJonathan Albrieux 
424b1037c1aSLinus Walleij 	/*
425c2ea1d0cSJonathan Albrieux 	 * According to the datasheet the power supply rise time is 200us
426b1037c1aSLinus Walleij 	 * and the minimum wait time before mode setting is 100us, in
427b1037c1aSLinus Walleij 	 * total 300us. Add some margin and say minimum 500us here.
428b1037c1aSLinus Walleij 	 */
429b1037c1aSLinus Walleij 	usleep_range(500, 1000);
430b21d3f34SLinus Walleij 	return 0;
43190e96fddSLinus Walleij }
432a9b72c90SGregor Boirie 
433a9b72c90SGregor Boirie /* Disable attached power regulator if any. */
ak8975_power_off(const struct ak8975_data * data)4349e6c16d9SLinus Walleij static void ak8975_power_off(const struct ak8975_data *data)
435a9b72c90SGregor Boirie {
4369604ed75SJonathan Albrieux 	gpiod_set_value_cansleep(data->reset_gpiod, 1);
4379604ed75SJonathan Albrieux 
438b21d3f34SLinus Walleij 	regulator_disable(data->vid);
439a9b72c90SGregor Boirie 	regulator_disable(data->vdd);
440a9b72c90SGregor Boirie }
441a9b72c90SGregor Boirie 
4422fc72cd8SJonathan Cameron /*
44357e73a42SGwendal Grignou  * Return 0 if the i2c device is the one we expect.
44457e73a42SGwendal Grignou  * return a negative error number otherwise
44557e73a42SGwendal Grignou  */
ak8975_who_i_am(struct i2c_client * client,enum asahi_compass_chipset type)44657e73a42SGwendal Grignou static int ak8975_who_i_am(struct i2c_client *client,
44757e73a42SGwendal Grignou 			   enum asahi_compass_chipset type)
44857e73a42SGwendal Grignou {
44957e73a42SGwendal Grignou 	u8 wia_val[2];
45057e73a42SGwendal Grignou 	int ret;
45157e73a42SGwendal Grignou 
45257e73a42SGwendal Grignou 	/*
45357e73a42SGwendal Grignou 	 * Signature for each device:
45457e73a42SGwendal Grignou 	 * Device   |  WIA1      |  WIA2
45576e28aa9SMatt Ranostay 	 * AK09916  |  DEVICE_ID_|  AK09916_DEVICE_ID
45657e73a42SGwendal Grignou 	 * AK09912  |  DEVICE_ID |  AK09912_DEVICE_ID
45757e73a42SGwendal Grignou 	 * AK09911  |  DEVICE_ID |  AK09911_DEVICE_ID
45857e73a42SGwendal Grignou 	 * AK8975   |  DEVICE_ID |  NA
45957e73a42SGwendal Grignou 	 * AK8963   |  DEVICE_ID |  NA
46057e73a42SGwendal Grignou 	 */
461a8175ba3SCrestez Dan Leonard 	ret = i2c_smbus_read_i2c_block_data_or_emulated(
462a8175ba3SCrestez Dan Leonard 			client, AK09912_REG_WIA1, 2, wia_val);
46357e73a42SGwendal Grignou 	if (ret < 0) {
46457e73a42SGwendal Grignou 		dev_err(&client->dev, "Error reading WIA\n");
46557e73a42SGwendal Grignou 		return ret;
46657e73a42SGwendal Grignou 	}
46757e73a42SGwendal Grignou 
46857e73a42SGwendal Grignou 	if (wia_val[0] != AK8975_DEVICE_ID)
46957e73a42SGwendal Grignou 		return -ENODEV;
47057e73a42SGwendal Grignou 
47157e73a42SGwendal Grignou 	switch (type) {
47257e73a42SGwendal Grignou 	case AK8975:
47357e73a42SGwendal Grignou 	case AK8963:
47457e73a42SGwendal Grignou 		return 0;
47557e73a42SGwendal Grignou 	case AK09911:
47657e73a42SGwendal Grignou 		if (wia_val[1] == AK09911_DEVICE_ID)
47757e73a42SGwendal Grignou 			return 0;
47857e73a42SGwendal Grignou 		break;
47957e73a42SGwendal Grignou 	case AK09912:
48057e73a42SGwendal Grignou 		if (wia_val[1] == AK09912_DEVICE_ID)
48157e73a42SGwendal Grignou 			return 0;
48257e73a42SGwendal Grignou 		break;
48376e28aa9SMatt Ranostay 	case AK09916:
48476e28aa9SMatt Ranostay 		if (wia_val[1] == AK09916_DEVICE_ID)
48576e28aa9SMatt Ranostay 			return 0;
48676e28aa9SMatt Ranostay 		break;
48757e73a42SGwendal Grignou 	default:
48857e73a42SGwendal Grignou 		dev_err(&client->dev, "Type %d unknown\n", type);
48957e73a42SGwendal Grignou 	}
49057e73a42SGwendal Grignou 	return -ENODEV;
49157e73a42SGwendal Grignou }
49257e73a42SGwendal Grignou 
49357e73a42SGwendal Grignou /*
494286f74c2SGwendal Grignou  * Helper function to write to CNTL register.
4952fc72cd8SJonathan Cameron  */
ak8975_set_mode(struct ak8975_data * data,enum ak_ctrl_mode mode)496286f74c2SGwendal Grignou static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
4972fc72cd8SJonathan Cameron {
4982fc72cd8SJonathan Cameron 	u8 regval;
4992fc72cd8SJonathan Cameron 	int ret;
5002fc72cd8SJonathan Cameron 
501286f74c2SGwendal Grignou 	regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
502286f74c2SGwendal Grignou 		 data->def->ctrl_modes[mode];
503286f74c2SGwendal Grignou 	ret = i2c_smbus_write_byte_data(data->client,
504286f74c2SGwendal Grignou 					data->def->ctrl_regs[CNTL], regval);
5052fc72cd8SJonathan Cameron 	if (ret < 0) {
5062fc72cd8SJonathan Cameron 		return ret;
5072fc72cd8SJonathan Cameron 	}
508286f74c2SGwendal Grignou 	data->cntl_cache = regval;
509286f74c2SGwendal Grignou 	/* After mode change wait atleast 100us */
510286f74c2SGwendal Grignou 	usleep_range(100, 500);
5112fc72cd8SJonathan Cameron 
5122fc72cd8SJonathan Cameron 	return 0;
5132fc72cd8SJonathan Cameron }
5142fc72cd8SJonathan Cameron 
5152fc72cd8SJonathan Cameron /*
51694a6d5cfSJacek Anaszewski  * Handle data ready irq
51794a6d5cfSJacek Anaszewski  */
ak8975_irq_handler(int irq,void * data)51894a6d5cfSJacek Anaszewski static irqreturn_t ak8975_irq_handler(int irq, void *data)
51994a6d5cfSJacek Anaszewski {
52094a6d5cfSJacek Anaszewski 	struct ak8975_data *ak8975 = data;
52194a6d5cfSJacek Anaszewski 
52294a6d5cfSJacek Anaszewski 	set_bit(0, &ak8975->flags);
52394a6d5cfSJacek Anaszewski 	wake_up(&ak8975->data_ready_queue);
52494a6d5cfSJacek Anaszewski 
52594a6d5cfSJacek Anaszewski 	return IRQ_HANDLED;
52694a6d5cfSJacek Anaszewski }
52794a6d5cfSJacek Anaszewski 
52894a6d5cfSJacek Anaszewski /*
52994a6d5cfSJacek Anaszewski  * Install data ready interrupt handler
53094a6d5cfSJacek Anaszewski  */
ak8975_setup_irq(struct ak8975_data * data)53194a6d5cfSJacek Anaszewski static int ak8975_setup_irq(struct ak8975_data *data)
53294a6d5cfSJacek Anaszewski {
53394a6d5cfSJacek Anaszewski 	struct i2c_client *client = data->client;
53494a6d5cfSJacek Anaszewski 	int rc;
53594a6d5cfSJacek Anaszewski 	int irq;
53694a6d5cfSJacek Anaszewski 
53707d2390eSKrzysztof Kozlowski 	init_waitqueue_head(&data->data_ready_queue);
53807d2390eSKrzysztof Kozlowski 	clear_bit(0, &data->flags);
53994a6d5cfSJacek Anaszewski 	if (client->irq)
54094a6d5cfSJacek Anaszewski 		irq = client->irq;
54194a6d5cfSJacek Anaszewski 	else
5422c289e63SLinus Walleij 		irq = gpiod_to_irq(data->eoc_gpiod);
54394a6d5cfSJacek Anaszewski 
544a845a3aaSBeomho Seo 	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
54594a6d5cfSJacek Anaszewski 			      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
54694a6d5cfSJacek Anaszewski 			      dev_name(&client->dev), data);
54794a6d5cfSJacek Anaszewski 	if (rc < 0) {
5482c289e63SLinus Walleij 		dev_err(&client->dev, "irq %d request failed: %d\n", irq, rc);
54994a6d5cfSJacek Anaszewski 		return rc;
55094a6d5cfSJacek Anaszewski 	}
55194a6d5cfSJacek Anaszewski 
55294a6d5cfSJacek Anaszewski 	data->eoc_irq = irq;
55394a6d5cfSJacek Anaszewski 
55494a6d5cfSJacek Anaszewski 	return rc;
55594a6d5cfSJacek Anaszewski }
55694a6d5cfSJacek Anaszewski 
55794a6d5cfSJacek Anaszewski 
55894a6d5cfSJacek Anaszewski /*
5592fc72cd8SJonathan Cameron  * Perform some start-of-day setup, including reading the asa calibration
5602fc72cd8SJonathan Cameron  * values and caching them.
5612fc72cd8SJonathan Cameron  */
ak8975_setup(struct i2c_client * client)5622fc72cd8SJonathan Cameron static int ak8975_setup(struct i2c_client *client)
5632fc72cd8SJonathan Cameron {
5642fc72cd8SJonathan Cameron 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
5652fc72cd8SJonathan Cameron 	struct ak8975_data *data = iio_priv(indio_dev);
5662fc72cd8SJonathan Cameron 	int ret;
5672fc72cd8SJonathan Cameron 
5682fc72cd8SJonathan Cameron 	/* Write the fused rom access mode. */
569286f74c2SGwendal Grignou 	ret = ak8975_set_mode(data, FUSE_ROM);
5702fc72cd8SJonathan Cameron 	if (ret < 0) {
5712fc72cd8SJonathan Cameron 		dev_err(&client->dev, "Error in setting fuse access mode\n");
5722fc72cd8SJonathan Cameron 		return ret;
5732fc72cd8SJonathan Cameron 	}
5742fc72cd8SJonathan Cameron 
5752fc72cd8SJonathan Cameron 	/* Get asa data and store in the device data. */
576a8175ba3SCrestez Dan Leonard 	ret = i2c_smbus_read_i2c_block_data_or_emulated(
577a8175ba3SCrestez Dan Leonard 			client, data->def->ctrl_regs[ASA_BASE],
5782fc72cd8SJonathan Cameron 			3, data->asa);
5792fc72cd8SJonathan Cameron 	if (ret < 0) {
5802fc72cd8SJonathan Cameron 		dev_err(&client->dev, "Not able to read asa data\n");
5812fc72cd8SJonathan Cameron 		return ret;
5822fc72cd8SJonathan Cameron 	}
5832fc72cd8SJonathan Cameron 
5842fc72cd8SJonathan Cameron 	/* After reading fuse ROM data set power-down mode */
585286f74c2SGwendal Grignou 	ret = ak8975_set_mode(data, POWER_DOWN);
58671222bf5SGwendal Grignou 	if (ret < 0) {
58771222bf5SGwendal Grignou 		dev_err(&client->dev, "Error in setting power-down mode\n");
58871222bf5SGwendal Grignou 		return ret;
58971222bf5SGwendal Grignou 	}
59094a6d5cfSJacek Anaszewski 
5912c289e63SLinus Walleij 	if (data->eoc_gpiod || client->irq > 0) {
59294a6d5cfSJacek Anaszewski 		ret = ak8975_setup_irq(data);
59394a6d5cfSJacek Anaszewski 		if (ret < 0) {
59494a6d5cfSJacek Anaszewski 			dev_err(&client->dev,
59594a6d5cfSJacek Anaszewski 				"Error setting data ready interrupt\n");
59694a6d5cfSJacek Anaszewski 			return ret;
59794a6d5cfSJacek Anaszewski 		}
59894a6d5cfSJacek Anaszewski 	}
59994a6d5cfSJacek Anaszewski 
600286f74c2SGwendal Grignou 	data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
601286f74c2SGwendal Grignou 	data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
602286f74c2SGwendal Grignou 	data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
6032fc72cd8SJonathan Cameron 
6042fc72cd8SJonathan Cameron 	return 0;
6052fc72cd8SJonathan Cameron }
6062fc72cd8SJonathan Cameron 
wait_conversion_complete_gpio(struct ak8975_data * data)6072fc72cd8SJonathan Cameron static int wait_conversion_complete_gpio(struct ak8975_data *data)
6082fc72cd8SJonathan Cameron {
6092fc72cd8SJonathan Cameron 	struct i2c_client *client = data->client;
6102fc72cd8SJonathan Cameron 	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
6112fc72cd8SJonathan Cameron 	int ret;
6122fc72cd8SJonathan Cameron 
6132fc72cd8SJonathan Cameron 	/* Wait for the conversion to complete. */
6142fc72cd8SJonathan Cameron 	while (timeout_ms) {
6152fc72cd8SJonathan Cameron 		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
6162c289e63SLinus Walleij 		if (gpiod_get_value(data->eoc_gpiod))
6172fc72cd8SJonathan Cameron 			break;
6182fc72cd8SJonathan Cameron 		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
6192fc72cd8SJonathan Cameron 	}
6202fc72cd8SJonathan Cameron 	if (!timeout_ms) {
6212fc72cd8SJonathan Cameron 		dev_err(&client->dev, "Conversion timeout happened\n");
6222fc72cd8SJonathan Cameron 		return -EINVAL;
6232fc72cd8SJonathan Cameron 	}
6242fc72cd8SJonathan Cameron 
625286f74c2SGwendal Grignou 	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
6262fc72cd8SJonathan Cameron 	if (ret < 0)
6272fc72cd8SJonathan Cameron 		dev_err(&client->dev, "Error in reading ST1\n");
6282fc72cd8SJonathan Cameron 
6292fc72cd8SJonathan Cameron 	return ret;
6302fc72cd8SJonathan Cameron }
6312fc72cd8SJonathan Cameron 
wait_conversion_complete_polled(struct ak8975_data * data)6322fc72cd8SJonathan Cameron static int wait_conversion_complete_polled(struct ak8975_data *data)
6332fc72cd8SJonathan Cameron {
6342fc72cd8SJonathan Cameron 	struct i2c_client *client = data->client;
6352fc72cd8SJonathan Cameron 	u8 read_status;
6362fc72cd8SJonathan Cameron 	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
6372fc72cd8SJonathan Cameron 	int ret;
6382fc72cd8SJonathan Cameron 
6392fc72cd8SJonathan Cameron 	/* Wait for the conversion to complete. */
6402fc72cd8SJonathan Cameron 	while (timeout_ms) {
6412fc72cd8SJonathan Cameron 		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
642286f74c2SGwendal Grignou 		ret = i2c_smbus_read_byte_data(client,
643286f74c2SGwendal Grignou 					       data->def->ctrl_regs[ST1]);
6442fc72cd8SJonathan Cameron 		if (ret < 0) {
6452fc72cd8SJonathan Cameron 			dev_err(&client->dev, "Error in reading ST1\n");
6462fc72cd8SJonathan Cameron 			return ret;
6472fc72cd8SJonathan Cameron 		}
6482fc72cd8SJonathan Cameron 		read_status = ret;
6492fc72cd8SJonathan Cameron 		if (read_status)
6502fc72cd8SJonathan Cameron 			break;
6512fc72cd8SJonathan Cameron 		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
6522fc72cd8SJonathan Cameron 	}
6532fc72cd8SJonathan Cameron 	if (!timeout_ms) {
6542fc72cd8SJonathan Cameron 		dev_err(&client->dev, "Conversion timeout happened\n");
6552fc72cd8SJonathan Cameron 		return -EINVAL;
6562fc72cd8SJonathan Cameron 	}
65794a6d5cfSJacek Anaszewski 
6582fc72cd8SJonathan Cameron 	return read_status;
6592fc72cd8SJonathan Cameron }
6602fc72cd8SJonathan Cameron 
66194a6d5cfSJacek Anaszewski /* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
wait_conversion_complete_interrupt(struct ak8975_data * data)66294a6d5cfSJacek Anaszewski static int wait_conversion_complete_interrupt(struct ak8975_data *data)
66394a6d5cfSJacek Anaszewski {
66494a6d5cfSJacek Anaszewski 	int ret;
66594a6d5cfSJacek Anaszewski 
66694a6d5cfSJacek Anaszewski 	ret = wait_event_timeout(data->data_ready_queue,
66794a6d5cfSJacek Anaszewski 				 test_bit(0, &data->flags),
66894a6d5cfSJacek Anaszewski 				 AK8975_DATA_READY_TIMEOUT);
66994a6d5cfSJacek Anaszewski 	clear_bit(0, &data->flags);
67094a6d5cfSJacek Anaszewski 
67194a6d5cfSJacek Anaszewski 	return ret > 0 ? 0 : -ETIME;
67294a6d5cfSJacek Anaszewski }
67394a6d5cfSJacek Anaszewski 
ak8975_start_read_axis(struct ak8975_data * data,const struct i2c_client * client)674bc11ca4aSGregor Boirie static int ak8975_start_read_axis(struct ak8975_data *data,
675bc11ca4aSGregor Boirie 				  const struct i2c_client *client)
6762fc72cd8SJonathan Cameron {
6772fc72cd8SJonathan Cameron 	/* Set up the device for taking a sample. */
678bc11ca4aSGregor Boirie 	int ret = ak8975_set_mode(data, MODE_ONCE);
679bc11ca4aSGregor Boirie 
6802fc72cd8SJonathan Cameron 	if (ret < 0) {
6812fc72cd8SJonathan Cameron 		dev_err(&client->dev, "Error in setting operating mode\n");
682bc11ca4aSGregor Boirie 		return ret;
6832fc72cd8SJonathan Cameron 	}
6842fc72cd8SJonathan Cameron 
6852fc72cd8SJonathan Cameron 	/* Wait for the conversion to complete. */
68694a6d5cfSJacek Anaszewski 	if (data->eoc_irq)
68794a6d5cfSJacek Anaszewski 		ret = wait_conversion_complete_interrupt(data);
6882c289e63SLinus Walleij 	else if (data->eoc_gpiod)
6892fc72cd8SJonathan Cameron 		ret = wait_conversion_complete_gpio(data);
6902fc72cd8SJonathan Cameron 	else
6912fc72cd8SJonathan Cameron 		ret = wait_conversion_complete_polled(data);
6922fc72cd8SJonathan Cameron 	if (ret < 0)
693bc11ca4aSGregor Boirie 		return ret;
6942fc72cd8SJonathan Cameron 
695*73328d2aSBarnabás Czémán 	/* Return with zero if the data is ready. */
696*73328d2aSBarnabás Czémán 	return !data->def->ctrl_regs[ST1_DRDY];
6972fc72cd8SJonathan Cameron }
6982fc72cd8SJonathan Cameron 
699bc11ca4aSGregor Boirie /* Retrieve raw flux value for one of the x, y, or z axis.  */
ak8975_read_axis(struct iio_dev * indio_dev,int index,int * val)700bc11ca4aSGregor Boirie static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
701bc11ca4aSGregor Boirie {
702bc11ca4aSGregor Boirie 	struct ak8975_data *data = iio_priv(indio_dev);
703bc11ca4aSGregor Boirie 	const struct i2c_client *client = data->client;
704bc11ca4aSGregor Boirie 	const struct ak_def *def = data->def;
70569c72ec9SSandhya Bankar 	__le16 rval;
706a8175ba3SCrestez Dan Leonard 	u16 buff;
707bc11ca4aSGregor Boirie 	int ret;
708bc11ca4aSGregor Boirie 
709cde4cb5dSLinus Walleij 	pm_runtime_get_sync(&data->client->dev);
710cde4cb5dSLinus Walleij 
711bc11ca4aSGregor Boirie 	mutex_lock(&data->lock);
712bc11ca4aSGregor Boirie 
713bc11ca4aSGregor Boirie 	ret = ak8975_start_read_axis(data, client);
714bc11ca4aSGregor Boirie 	if (ret)
715bc11ca4aSGregor Boirie 		goto exit;
716bc11ca4aSGregor Boirie 
717a8175ba3SCrestez Dan Leonard 	ret = i2c_smbus_read_i2c_block_data_or_emulated(
718a8175ba3SCrestez Dan Leonard 			client, def->data_regs[index],
71969c72ec9SSandhya Bankar 			sizeof(rval), (u8*)&rval);
720bc11ca4aSGregor Boirie 	if (ret < 0)
721bc11ca4aSGregor Boirie 		goto exit;
722bc11ca4aSGregor Boirie 
723*73328d2aSBarnabás Czémán 	/* Read out ST2 for release lock on measurment data. */
724*73328d2aSBarnabás Czémán 	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST2]);
725*73328d2aSBarnabás Czémán 	if (ret < 0) {
726*73328d2aSBarnabás Czémán 		dev_err(&client->dev, "Error in reading ST2\n");
727*73328d2aSBarnabás Czémán 		goto exit;
728*73328d2aSBarnabás Czémán 	}
729*73328d2aSBarnabás Czémán 
730*73328d2aSBarnabás Czémán 	if (ret & (data->def->ctrl_masks[ST2_DERR] |
731*73328d2aSBarnabás Czémán 		   data->def->ctrl_masks[ST2_HOFL])) {
732*73328d2aSBarnabás Czémán 		dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
733*73328d2aSBarnabás Czémán 		ret = -EINVAL;
734*73328d2aSBarnabás Czémán 		goto exit;
735*73328d2aSBarnabás Czémán 	}
736*73328d2aSBarnabás Czémán 
7372fc72cd8SJonathan Cameron 	mutex_unlock(&data->lock);
7382fc72cd8SJonathan Cameron 
739cde4cb5dSLinus Walleij 	pm_runtime_mark_last_busy(&data->client->dev);
740cde4cb5dSLinus Walleij 	pm_runtime_put_autosuspend(&data->client->dev);
741cde4cb5dSLinus Walleij 
742a8175ba3SCrestez Dan Leonard 	/* Swap bytes and convert to valid range. */
74369c72ec9SSandhya Bankar 	buff = le16_to_cpu(rval);
744a8175ba3SCrestez Dan Leonard 	*val = clamp_t(s16, buff, -def->range, def->range);
7452fc72cd8SJonathan Cameron 	return IIO_VAL_INT;
7462fc72cd8SJonathan Cameron 
7472fc72cd8SJonathan Cameron exit:
7482fc72cd8SJonathan Cameron 	mutex_unlock(&data->lock);
749bc11ca4aSGregor Boirie 	dev_err(&client->dev, "Error in reading axis\n");
7502fc72cd8SJonathan Cameron 	return ret;
7512fc72cd8SJonathan Cameron }
7522fc72cd8SJonathan Cameron 
ak8975_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)7532fc72cd8SJonathan Cameron static int ak8975_read_raw(struct iio_dev *indio_dev,
7542fc72cd8SJonathan Cameron 			   struct iio_chan_spec const *chan,
7552fc72cd8SJonathan Cameron 			   int *val, int *val2,
7562fc72cd8SJonathan Cameron 			   long mask)
7572fc72cd8SJonathan Cameron {
7582fc72cd8SJonathan Cameron 	struct ak8975_data *data = iio_priv(indio_dev);
7592fc72cd8SJonathan Cameron 
7602fc72cd8SJonathan Cameron 	switch (mask) {
7612fc72cd8SJonathan Cameron 	case IIO_CHAN_INFO_RAW:
7622fc72cd8SJonathan Cameron 		return ak8975_read_axis(indio_dev, chan->address, val);
7632fc72cd8SJonathan Cameron 	case IIO_CHAN_INFO_SCALE:
764bef44abcSBeomho Seo 		*val = 0;
765bef44abcSBeomho Seo 		*val2 = data->raw_to_gauss[chan->address];
766bef44abcSBeomho Seo 		return IIO_VAL_INT_PLUS_MICRO;
7672fc72cd8SJonathan Cameron 	}
7682fc72cd8SJonathan Cameron 	return -EINVAL;
7692fc72cd8SJonathan Cameron }
7702fc72cd8SJonathan Cameron 
77197eacb91SGregor Boirie static const struct iio_mount_matrix *
ak8975_get_mount_matrix(const struct iio_dev * indio_dev,const struct iio_chan_spec * chan)77297eacb91SGregor Boirie ak8975_get_mount_matrix(const struct iio_dev *indio_dev,
77397eacb91SGregor Boirie 			const struct iio_chan_spec *chan)
77497eacb91SGregor Boirie {
77567b9d4d0SH. Nikolaus Schaller 	struct ak8975_data *data = iio_priv(indio_dev);
77667b9d4d0SH. Nikolaus Schaller 
77767b9d4d0SH. Nikolaus Schaller 	return &data->orientation;
77897eacb91SGregor Boirie }
77997eacb91SGregor Boirie 
78097eacb91SGregor Boirie static const struct iio_chan_spec_ext_info ak8975_ext_info[] = {
78197eacb91SGregor Boirie 	IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, ak8975_get_mount_matrix),
78267b9d4d0SH. Nikolaus Schaller 	{ }
78397eacb91SGregor Boirie };
78497eacb91SGregor Boirie 
7852fc72cd8SJonathan Cameron #define AK8975_CHANNEL(axis, index)					\
7862fc72cd8SJonathan Cameron 	{								\
7872fc72cd8SJonathan Cameron 		.type = IIO_MAGN,					\
7882fc72cd8SJonathan Cameron 		.modified = 1,						\
7892fc72cd8SJonathan Cameron 		.channel2 = IIO_MOD_##axis,				\
7902fc72cd8SJonathan Cameron 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
7912fc72cd8SJonathan Cameron 			     BIT(IIO_CHAN_INFO_SCALE),			\
7922fc72cd8SJonathan Cameron 		.address = index,					\
793bc11ca4aSGregor Boirie 		.scan_index = index,					\
794bc11ca4aSGregor Boirie 		.scan_type = {						\
795bc11ca4aSGregor Boirie 			.sign = 's',					\
796bc11ca4aSGregor Boirie 			.realbits = 16,					\
797bc11ca4aSGregor Boirie 			.storagebits = 16,				\
798bc11ca4aSGregor Boirie 			.endianness = IIO_CPU				\
79997eacb91SGregor Boirie 		},							\
80097eacb91SGregor Boirie 		.ext_info = ak8975_ext_info,				\
8012fc72cd8SJonathan Cameron 	}
8022fc72cd8SJonathan Cameron 
8032fc72cd8SJonathan Cameron static const struct iio_chan_spec ak8975_channels[] = {
8042fc72cd8SJonathan Cameron 	AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
805bc11ca4aSGregor Boirie 	IIO_CHAN_SOFT_TIMESTAMP(3),
8062fc72cd8SJonathan Cameron };
8072fc72cd8SJonathan Cameron 
808bc11ca4aSGregor Boirie static const unsigned long ak8975_scan_masks[] = { 0x7, 0 };
809bc11ca4aSGregor Boirie 
8102fc72cd8SJonathan Cameron static const struct iio_info ak8975_info = {
8112fc72cd8SJonathan Cameron 	.read_raw = &ak8975_read_raw,
8122fc72cd8SJonathan Cameron };
8132fc72cd8SJonathan Cameron 
814d913971eSSrinivas Pandruvada static const struct acpi_device_id ak_acpi_match[] = {
815c5a4a276SBiju Das 	{"AK8975", (kernel_ulong_t)&ak_def_array[AK8975] },
816c5a4a276SBiju Das 	{"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] },
817c5a4a276SBiju Das 	{"INVN6500", (kernel_ulong_t)&ak_def_array[AK8963] },
818c5a4a276SBiju Das 	{"AK009911", (kernel_ulong_t)&ak_def_array[AK09911] },
819c5a4a276SBiju Das 	{"AK09911", (kernel_ulong_t)&ak_def_array[AK09911] },
820c5a4a276SBiju Das 	{"AKM9911", (kernel_ulong_t)&ak_def_array[AK09911] },
821c5a4a276SBiju Das 	{"AK09912", (kernel_ulong_t)&ak_def_array[AK09912] },
82267b9d4d0SH. Nikolaus Schaller 	{ }
823d913971eSSrinivas Pandruvada };
824d913971eSSrinivas Pandruvada MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
825d913971eSSrinivas Pandruvada 
ak8975_fill_buffer(struct iio_dev * indio_dev)826bc11ca4aSGregor Boirie static void ak8975_fill_buffer(struct iio_dev *indio_dev)
827bc11ca4aSGregor Boirie {
828bc11ca4aSGregor Boirie 	struct ak8975_data *data = iio_priv(indio_dev);
829bc11ca4aSGregor Boirie 	const struct i2c_client *client = data->client;
830bc11ca4aSGregor Boirie 	const struct ak_def *def = data->def;
831bc11ca4aSGregor Boirie 	int ret;
83269c72ec9SSandhya Bankar 	__le16 fval[3];
833bc11ca4aSGregor Boirie 
834bc11ca4aSGregor Boirie 	mutex_lock(&data->lock);
835bc11ca4aSGregor Boirie 
836bc11ca4aSGregor Boirie 	ret = ak8975_start_read_axis(data, client);
837bc11ca4aSGregor Boirie 	if (ret)
838bc11ca4aSGregor Boirie 		goto unlock;
839bc11ca4aSGregor Boirie 
840bc11ca4aSGregor Boirie 	/*
841bc11ca4aSGregor Boirie 	 * For each axis, read the flux value from the appropriate register
842bc11ca4aSGregor Boirie 	 * (the register is specified in the iio device attributes).
843bc11ca4aSGregor Boirie 	 */
844bc11ca4aSGregor Boirie 	ret = i2c_smbus_read_i2c_block_data_or_emulated(client,
845bc11ca4aSGregor Boirie 							def->data_regs[0],
84669c72ec9SSandhya Bankar 							3 * sizeof(fval[0]),
84769c72ec9SSandhya Bankar 							(u8 *)fval);
848bc11ca4aSGregor Boirie 	if (ret < 0)
849bc11ca4aSGregor Boirie 		goto unlock;
850bc11ca4aSGregor Boirie 
851bc11ca4aSGregor Boirie 	mutex_unlock(&data->lock);
852bc11ca4aSGregor Boirie 
853bc11ca4aSGregor Boirie 	/* Clamp to valid range. */
85402ad21ceSJonathan Cameron 	data->scan.channels[0] = clamp_t(s16, le16_to_cpu(fval[0]), -def->range, def->range);
85502ad21ceSJonathan Cameron 	data->scan.channels[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range);
85602ad21ceSJonathan Cameron 	data->scan.channels[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range);
857bc11ca4aSGregor Boirie 
85802ad21ceSJonathan Cameron 	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
859bc2b7dabSGregor Boirie 					   iio_get_time_ns(indio_dev));
86002ad21ceSJonathan Cameron 
861bc11ca4aSGregor Boirie 	return;
862bc11ca4aSGregor Boirie 
863bc11ca4aSGregor Boirie unlock:
864bc11ca4aSGregor Boirie 	mutex_unlock(&data->lock);
865bc11ca4aSGregor Boirie 	dev_err(&client->dev, "Error in reading axes block\n");
866bc11ca4aSGregor Boirie }
867bc11ca4aSGregor Boirie 
ak8975_handle_trigger(int irq,void * p)868bc11ca4aSGregor Boirie static irqreturn_t ak8975_handle_trigger(int irq, void *p)
869bc11ca4aSGregor Boirie {
870bc11ca4aSGregor Boirie 	const struct iio_poll_func *pf = p;
871bc11ca4aSGregor Boirie 	struct iio_dev *indio_dev = pf->indio_dev;
872bc11ca4aSGregor Boirie 
873bc11ca4aSGregor Boirie 	ak8975_fill_buffer(indio_dev);
874bc11ca4aSGregor Boirie 	iio_trigger_notify_done(indio_dev->trig);
875bc11ca4aSGregor Boirie 	return IRQ_HANDLED;
876bc11ca4aSGregor Boirie }
877bc11ca4aSGregor Boirie 
ak8975_probe(struct i2c_client * client)878f64eeceaSUwe Kleine-König static int ak8975_probe(struct i2c_client *client)
8792fc72cd8SJonathan Cameron {
880f64eeceaSUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
8812fc72cd8SJonathan Cameron 	struct ak8975_data *data;
8822fc72cd8SJonathan Cameron 	struct iio_dev *indio_dev;
8832c289e63SLinus Walleij 	struct gpio_desc *eoc_gpiod;
8849604ed75SJonathan Albrieux 	struct gpio_desc *reset_gpiod;
8852fc72cd8SJonathan Cameron 	int err;
88648edc374SIrina Tirdea 	const char *name = NULL;
8872fc72cd8SJonathan Cameron 
8882c289e63SLinus Walleij 	/*
8892c289e63SLinus Walleij 	 * Grab and set up the supplied GPIO.
8902c289e63SLinus Walleij 	 * We may not have a GPIO based IRQ to scan, that is fine, we will
8912c289e63SLinus Walleij 	 * poll if so.
8922c289e63SLinus Walleij 	 */
8932c289e63SLinus Walleij 	eoc_gpiod = devm_gpiod_get_optional(&client->dev, NULL, GPIOD_IN);
8942c289e63SLinus Walleij 	if (IS_ERR(eoc_gpiod))
8952c289e63SLinus Walleij 		return PTR_ERR(eoc_gpiod);
8962c289e63SLinus Walleij 	if (eoc_gpiod)
8972c289e63SLinus Walleij 		gpiod_set_consumer_name(eoc_gpiod, "ak_8975");
8982fc72cd8SJonathan Cameron 
8999604ed75SJonathan Albrieux 	/*
9009604ed75SJonathan Albrieux 	 * According to AK09911 datasheet, if reset GPIO is provided then
9019604ed75SJonathan Albrieux 	 * deassert reset on ak8975_power_on() and assert reset on
9029604ed75SJonathan Albrieux 	 * ak8975_power_off().
9039604ed75SJonathan Albrieux 	 */
9049604ed75SJonathan Albrieux 	reset_gpiod = devm_gpiod_get_optional(&client->dev,
9059604ed75SJonathan Albrieux 					      "reset", GPIOD_OUT_HIGH);
9069604ed75SJonathan Albrieux 	if (IS_ERR(reset_gpiod))
9079604ed75SJonathan Albrieux 		return PTR_ERR(reset_gpiod);
9089604ed75SJonathan Albrieux 
9092fc72cd8SJonathan Cameron 	/* Register with IIO */
910a845a3aaSBeomho Seo 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
911a845a3aaSBeomho Seo 	if (indio_dev == NULL)
912a845a3aaSBeomho Seo 		return -ENOMEM;
913a845a3aaSBeomho Seo 
9142fc72cd8SJonathan Cameron 	data = iio_priv(indio_dev);
9152fc72cd8SJonathan Cameron 	i2c_set_clientdata(client, indio_dev);
91694a6d5cfSJacek Anaszewski 
91794a6d5cfSJacek Anaszewski 	data->client = client;
9182c289e63SLinus Walleij 	data->eoc_gpiod = eoc_gpiod;
9199604ed75SJonathan Albrieux 	data->reset_gpiod = reset_gpiod;
92094a6d5cfSJacek Anaszewski 	data->eoc_irq = 0;
92194a6d5cfSJacek Anaszewski 
922b892770aSAndy Shevchenko 	err = iio_read_mount_matrix(&client->dev, &data->orientation);
92397eacb91SGregor Boirie 	if (err)
92497eacb91SGregor Boirie 		return err;
92597eacb91SGregor Boirie 
926d913971eSSrinivas Pandruvada 	/* id will be NULL when enumerated via ACPI */
927c5a4a276SBiju Das 	data->def = i2c_get_match_data(client);
928c5a4a276SBiju Das 	if (!data->def)
929286f74c2SGwendal Grignou 		return -ENODEV;
930286f74c2SGwendal Grignou 
931c5a4a276SBiju Das 	/* If enumerated via firmware node, fix the ABI */
932c5a4a276SBiju Das 	if (dev_fwnode(&client->dev))
933c5a4a276SBiju Das 		name = dev_name(&client->dev);
934c5a4a276SBiju Das 	else
935c5a4a276SBiju Das 		name = id->name;
936a9b72c90SGregor Boirie 
9379e6c16d9SLinus Walleij 	/* Fetch the regulators */
9389e6c16d9SLinus Walleij 	data->vdd = devm_regulator_get(&client->dev, "vdd");
9399e6c16d9SLinus Walleij 	if (IS_ERR(data->vdd))
9409e6c16d9SLinus Walleij 		return PTR_ERR(data->vdd);
9419e6c16d9SLinus Walleij 	data->vid = devm_regulator_get(&client->dev, "vid");
9429e6c16d9SLinus Walleij 	if (IS_ERR(data->vid))
9439e6c16d9SLinus Walleij 		return PTR_ERR(data->vid);
9449e6c16d9SLinus Walleij 
9459e6c16d9SLinus Walleij 	err = ak8975_power_on(data);
946a9b72c90SGregor Boirie 	if (err)
947a9b72c90SGregor Boirie 		return err;
948a9b72c90SGregor Boirie 
94957e73a42SGwendal Grignou 	err = ak8975_who_i_am(client, data->def->type);
95057e73a42SGwendal Grignou 	if (err < 0) {
95157e73a42SGwendal Grignou 		dev_err(&client->dev, "Unexpected device\n");
952a9b72c90SGregor Boirie 		goto power_off;
95357e73a42SGwendal Grignou 	}
954d913971eSSrinivas Pandruvada 	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
9556027c077SSrinivas Pandruvada 
9562fc72cd8SJonathan Cameron 	/* Perform some basic start-of-day setup of the device. */
9572fc72cd8SJonathan Cameron 	err = ak8975_setup(client);
9582fc72cd8SJonathan Cameron 	if (err < 0) {
95971222bf5SGwendal Grignou 		dev_err(&client->dev, "%s initialization fails\n", name);
960a9b72c90SGregor Boirie 		goto power_off;
9612fc72cd8SJonathan Cameron 	}
9622fc72cd8SJonathan Cameron 
9632fc72cd8SJonathan Cameron 	mutex_init(&data->lock);
9642fc72cd8SJonathan Cameron 	indio_dev->channels = ak8975_channels;
9652fc72cd8SJonathan Cameron 	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
9662fc72cd8SJonathan Cameron 	indio_dev->info = &ak8975_info;
967bc11ca4aSGregor Boirie 	indio_dev->available_scan_masks = ak8975_scan_masks;
9682fc72cd8SJonathan Cameron 	indio_dev->modes = INDIO_DIRECT_MODE;
969d913971eSSrinivas Pandruvada 	indio_dev->name = name;
970a9b72c90SGregor Boirie 
971bc11ca4aSGregor Boirie 	err = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger,
972bc11ca4aSGregor Boirie 					 NULL);
973bc11ca4aSGregor Boirie 	if (err) {
974bc11ca4aSGregor Boirie 		dev_err(&client->dev, "triggered buffer setup failed\n");
975a9b72c90SGregor Boirie 		goto power_off;
976bc11ca4aSGregor Boirie 	}
977bc11ca4aSGregor Boirie 
978bc11ca4aSGregor Boirie 	err = iio_device_register(indio_dev);
979bc11ca4aSGregor Boirie 	if (err) {
980bc11ca4aSGregor Boirie 		dev_err(&client->dev, "device register failed\n");
981bc11ca4aSGregor Boirie 		goto cleanup_buffer;
982bc11ca4aSGregor Boirie 	}
983a9b72c90SGregor Boirie 
984cde4cb5dSLinus Walleij 	/* Enable runtime PM */
985cde4cb5dSLinus Walleij 	pm_runtime_get_noresume(&client->dev);
986cde4cb5dSLinus Walleij 	pm_runtime_set_active(&client->dev);
987cde4cb5dSLinus Walleij 	pm_runtime_enable(&client->dev);
988cde4cb5dSLinus Walleij 	/*
989cde4cb5dSLinus Walleij 	 * The device comes online in 500us, so add two orders of magnitude
990cde4cb5dSLinus Walleij 	 * of delay before autosuspending: 50 ms.
991cde4cb5dSLinus Walleij 	 */
992cde4cb5dSLinus Walleij 	pm_runtime_set_autosuspend_delay(&client->dev, 50);
993cde4cb5dSLinus Walleij 	pm_runtime_use_autosuspend(&client->dev);
994cde4cb5dSLinus Walleij 	pm_runtime_put(&client->dev);
995cde4cb5dSLinus Walleij 
996a9b72c90SGregor Boirie 	return 0;
997a9b72c90SGregor Boirie 
998bc11ca4aSGregor Boirie cleanup_buffer:
999bc11ca4aSGregor Boirie 	iio_triggered_buffer_cleanup(indio_dev);
1000a9b72c90SGregor Boirie power_off:
10019e6c16d9SLinus Walleij 	ak8975_power_off(data);
1002a9b72c90SGregor Boirie 	return err;
1003a9b72c90SGregor Boirie }
1004a9b72c90SGregor Boirie 
ak8975_remove(struct i2c_client * client)1005ed5c2f5fSUwe Kleine-König static void ak8975_remove(struct i2c_client *client)
1006a9b72c90SGregor Boirie {
1007a9b72c90SGregor Boirie 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
10089e6c16d9SLinus Walleij 	struct ak8975_data *data = iio_priv(indio_dev);
1009a9b72c90SGregor Boirie 
1010cde4cb5dSLinus Walleij 	pm_runtime_get_sync(&client->dev);
1011cde4cb5dSLinus Walleij 	pm_runtime_put_noidle(&client->dev);
1012cde4cb5dSLinus Walleij 	pm_runtime_disable(&client->dev);
1013a9b72c90SGregor Boirie 	iio_device_unregister(indio_dev);
1014bc11ca4aSGregor Boirie 	iio_triggered_buffer_cleanup(indio_dev);
10158d06cd25SLinus Walleij 	ak8975_set_mode(data, POWER_DOWN);
10169e6c16d9SLinus Walleij 	ak8975_power_off(data);
10172fc72cd8SJonathan Cameron }
10182fc72cd8SJonathan Cameron 
ak8975_runtime_suspend(struct device * dev)1019cde4cb5dSLinus Walleij static int ak8975_runtime_suspend(struct device *dev)
1020cde4cb5dSLinus Walleij {
1021cde4cb5dSLinus Walleij 	struct i2c_client *client = to_i2c_client(dev);
1022cde4cb5dSLinus Walleij 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
1023cde4cb5dSLinus Walleij 	struct ak8975_data *data = iio_priv(indio_dev);
1024cde4cb5dSLinus Walleij 	int ret;
1025cde4cb5dSLinus Walleij 
1026cde4cb5dSLinus Walleij 	/* Set the device in power down if it wasn't already */
1027cde4cb5dSLinus Walleij 	ret = ak8975_set_mode(data, POWER_DOWN);
1028cde4cb5dSLinus Walleij 	if (ret < 0) {
1029cde4cb5dSLinus Walleij 		dev_err(&client->dev, "Error in setting power-down mode\n");
1030cde4cb5dSLinus Walleij 		return ret;
1031cde4cb5dSLinus Walleij 	}
1032cde4cb5dSLinus Walleij 	/* Next cut the regulators */
1033cde4cb5dSLinus Walleij 	ak8975_power_off(data);
1034cde4cb5dSLinus Walleij 
1035cde4cb5dSLinus Walleij 	return 0;
1036cde4cb5dSLinus Walleij }
1037cde4cb5dSLinus Walleij 
ak8975_runtime_resume(struct device * dev)1038cde4cb5dSLinus Walleij static int ak8975_runtime_resume(struct device *dev)
1039cde4cb5dSLinus Walleij {
1040cde4cb5dSLinus Walleij 	struct i2c_client *client = to_i2c_client(dev);
1041cde4cb5dSLinus Walleij 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
1042cde4cb5dSLinus Walleij 	struct ak8975_data *data = iio_priv(indio_dev);
1043cde4cb5dSLinus Walleij 	int ret;
1044cde4cb5dSLinus Walleij 
1045cde4cb5dSLinus Walleij 	/* Take up the regulators */
1046cde4cb5dSLinus Walleij 	ak8975_power_on(data);
1047cde4cb5dSLinus Walleij 	/*
1048cde4cb5dSLinus Walleij 	 * We come up in powered down mode, the reading routines will
1049cde4cb5dSLinus Walleij 	 * put us in the mode to read values later.
1050cde4cb5dSLinus Walleij 	 */
1051cde4cb5dSLinus Walleij 	ret = ak8975_set_mode(data, POWER_DOWN);
1052cde4cb5dSLinus Walleij 	if (ret < 0) {
1053cde4cb5dSLinus Walleij 		dev_err(&client->dev, "Error in setting power-down mode\n");
1054cde4cb5dSLinus Walleij 		return ret;
1055cde4cb5dSLinus Walleij 	}
1056cde4cb5dSLinus Walleij 
1057cde4cb5dSLinus Walleij 	return 0;
1058cde4cb5dSLinus Walleij }
1059cde4cb5dSLinus Walleij 
10606c1318f2SJonathan Cameron static DEFINE_RUNTIME_DEV_PM_OPS(ak8975_dev_pm_ops, ak8975_runtime_suspend,
10616c1318f2SJonathan Cameron 				 ak8975_runtime_resume, NULL);
1062cde4cb5dSLinus Walleij 
10632fc72cd8SJonathan Cameron static const struct i2c_device_id ak8975_id[] = {
1064c5a4a276SBiju Das 	{"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] },
1065c5a4a276SBiju Das 	{"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] },
1066c5a4a276SBiju Das 	{"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] },
1067c5a4a276SBiju Das 	{"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] },
1068c5a4a276SBiju Das 	{"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] },
1069c5a4a276SBiju Das 	{"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] },
10702fc72cd8SJonathan Cameron 	{}
10712fc72cd8SJonathan Cameron };
10722fc72cd8SJonathan Cameron 
10732fc72cd8SJonathan Cameron MODULE_DEVICE_TABLE(i2c, ak8975_id);
10742fc72cd8SJonathan Cameron 
10752fc72cd8SJonathan Cameron static const struct of_device_id ak8975_of_match[] = {
1076c5a4a276SBiju Das 	{ .compatible = "asahi-kasei,ak8975", .data = &ak_def_array[AK8975] },
1077c5a4a276SBiju Das 	{ .compatible = "ak8975", .data = &ak_def_array[AK8975] },
1078c5a4a276SBiju Das 	{ .compatible = "asahi-kasei,ak8963", .data = &ak_def_array[AK8963] },
1079c5a4a276SBiju Das 	{ .compatible = "ak8963", .data = &ak_def_array[AK8963] },
1080c5a4a276SBiju Das 	{ .compatible = "asahi-kasei,ak09911", .data = &ak_def_array[AK09911] },
1081c5a4a276SBiju Das 	{ .compatible = "ak09911", .data = &ak_def_array[AK09911] },
1082c5a4a276SBiju Das 	{ .compatible = "asahi-kasei,ak09912", .data = &ak_def_array[AK09912] },
1083c5a4a276SBiju Das 	{ .compatible = "ak09912", .data = &ak_def_array[AK09912] },
1084c5a4a276SBiju Das 	{ .compatible = "asahi-kasei,ak09916", .data = &ak_def_array[AK09916] },
10852fc72cd8SJonathan Cameron 	{}
10862fc72cd8SJonathan Cameron };
10872fc72cd8SJonathan Cameron MODULE_DEVICE_TABLE(of, ak8975_of_match);
10882fc72cd8SJonathan Cameron 
10892fc72cd8SJonathan Cameron static struct i2c_driver ak8975_driver = {
10902fc72cd8SJonathan Cameron 	.driver = {
10912fc72cd8SJonathan Cameron 		.name	= "ak8975",
10926c1318f2SJonathan Cameron 		.pm = pm_ptr(&ak8975_dev_pm_ops),
10938e5a0426SJonathan Cameron 		.of_match_table = ak8975_of_match,
10948e5a0426SJonathan Cameron 		.acpi_match_table = ak_acpi_match,
10952fc72cd8SJonathan Cameron 	},
10967cf15f42SUwe Kleine-König 	.probe		= ak8975_probe,
1097a9b72c90SGregor Boirie 	.remove		= ak8975_remove,
10982fc72cd8SJonathan Cameron 	.id_table	= ak8975_id,
10992fc72cd8SJonathan Cameron };
11002fc72cd8SJonathan Cameron module_i2c_driver(ak8975_driver);
11012fc72cd8SJonathan Cameron 
11022fc72cd8SJonathan Cameron MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
11032fc72cd8SJonathan Cameron MODULE_DESCRIPTION("AK8975 magnetometer driver");
11042fc72cd8SJonathan Cameron MODULE_LICENSE("GPL");
1105