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