1a0701b62SRui Miguel Silva // SPDX-License-Identifier: GPL-2.0
2a0701b62SRui Miguel Silva /*
3a0701b62SRui Miguel Silva * Driver for NXP FXAS21002C Gyroscope - Core
4a0701b62SRui Miguel Silva *
5a0701b62SRui Miguel Silva * Copyright (C) 2019 Linaro Ltd.
6a0701b62SRui Miguel Silva */
7a0701b62SRui Miguel Silva
8a0701b62SRui Miguel Silva #include <linux/interrupt.h>
9a0701b62SRui Miguel Silva #include <linux/module.h>
10a0701b62SRui Miguel Silva #include <linux/pm.h>
11a0701b62SRui Miguel Silva #include <linux/pm_runtime.h>
1261b9c4c7SAndy Shevchenko #include <linux/property.h>
13a0701b62SRui Miguel Silva #include <linux/regmap.h>
14a0701b62SRui Miguel Silva #include <linux/regulator/consumer.h>
15a0701b62SRui Miguel Silva
16a0701b62SRui Miguel Silva #include <linux/iio/events.h>
17a0701b62SRui Miguel Silva #include <linux/iio/iio.h>
18a0701b62SRui Miguel Silva #include <linux/iio/buffer.h>
19a0701b62SRui Miguel Silva #include <linux/iio/sysfs.h>
20a0701b62SRui Miguel Silva #include <linux/iio/trigger.h>
21a0701b62SRui Miguel Silva #include <linux/iio/trigger_consumer.h>
22a0701b62SRui Miguel Silva #include <linux/iio/triggered_buffer.h>
23a0701b62SRui Miguel Silva
24a0701b62SRui Miguel Silva #include "fxas21002c.h"
25a0701b62SRui Miguel Silva
26a0701b62SRui Miguel Silva #define FXAS21002C_CHIP_ID_1 0xD6
27a0701b62SRui Miguel Silva #define FXAS21002C_CHIP_ID_2 0xD7
28a0701b62SRui Miguel Silva
29a0701b62SRui Miguel Silva enum fxas21002c_mode_state {
30a0701b62SRui Miguel Silva FXAS21002C_MODE_STANDBY,
31a0701b62SRui Miguel Silva FXAS21002C_MODE_READY,
32a0701b62SRui Miguel Silva FXAS21002C_MODE_ACTIVE,
33a0701b62SRui Miguel Silva };
34a0701b62SRui Miguel Silva
35a0701b62SRui Miguel Silva #define FXAS21002C_STANDBY_ACTIVE_TIME_MS 62
36a0701b62SRui Miguel Silva #define FXAS21002C_READY_ACTIVE_TIME_MS 7
37a0701b62SRui Miguel Silva
38a0701b62SRui Miguel Silva #define FXAS21002C_ODR_LIST_MAX 10
39a0701b62SRui Miguel Silva
40a0701b62SRui Miguel Silva #define FXAS21002C_SCALE_FRACTIONAL 32
41a0701b62SRui Miguel Silva #define FXAS21002C_RANGE_LIMIT_DOUBLE 2000
42a0701b62SRui Miguel Silva
43a0701b62SRui Miguel Silva #define FXAS21002C_AXIS_TO_REG(axis) (FXAS21002C_REG_OUT_X_MSB + ((axis) * 2))
44a0701b62SRui Miguel Silva
45bfec5753SLee Jones static const struct reg_field fxas21002c_reg_fields[] = {
46bfec5753SLee Jones [F_DR_STATUS] = REG_FIELD(FXAS21002C_REG_STATUS, 0, 7),
47bfec5753SLee Jones [F_OUT_X_MSB] = REG_FIELD(FXAS21002C_REG_OUT_X_MSB, 0, 7),
48bfec5753SLee Jones [F_OUT_X_LSB] = REG_FIELD(FXAS21002C_REG_OUT_X_LSB, 0, 7),
49bfec5753SLee Jones [F_OUT_Y_MSB] = REG_FIELD(FXAS21002C_REG_OUT_Y_MSB, 0, 7),
50bfec5753SLee Jones [F_OUT_Y_LSB] = REG_FIELD(FXAS21002C_REG_OUT_Y_LSB, 0, 7),
51bfec5753SLee Jones [F_OUT_Z_MSB] = REG_FIELD(FXAS21002C_REG_OUT_Z_MSB, 0, 7),
52bfec5753SLee Jones [F_OUT_Z_LSB] = REG_FIELD(FXAS21002C_REG_OUT_Z_LSB, 0, 7),
53bfec5753SLee Jones [F_ZYX_OW] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 7, 7),
54bfec5753SLee Jones [F_Z_OW] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 6, 6),
55bfec5753SLee Jones [F_Y_OW] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 5, 5),
56bfec5753SLee Jones [F_X_OW] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 4, 4),
57bfec5753SLee Jones [F_ZYX_DR] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 3, 3),
58bfec5753SLee Jones [F_Z_DR] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 2, 2),
59bfec5753SLee Jones [F_Y_DR] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 1, 1),
60bfec5753SLee Jones [F_X_DR] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 0, 0),
61bfec5753SLee Jones [F_OVF] = REG_FIELD(FXAS21002C_REG_F_STATUS, 7, 7),
62bfec5753SLee Jones [F_WMKF] = REG_FIELD(FXAS21002C_REG_F_STATUS, 6, 6),
63bfec5753SLee Jones [F_CNT] = REG_FIELD(FXAS21002C_REG_F_STATUS, 0, 5),
64bfec5753SLee Jones [F_MODE] = REG_FIELD(FXAS21002C_REG_F_SETUP, 6, 7),
65bfec5753SLee Jones [F_WMRK] = REG_FIELD(FXAS21002C_REG_F_SETUP, 0, 5),
66bfec5753SLee Jones [F_EVENT] = REG_FIELD(FXAS21002C_REG_F_EVENT, 5, 5),
67bfec5753SLee Jones [FE_TIME] = REG_FIELD(FXAS21002C_REG_F_EVENT, 0, 4),
68bfec5753SLee Jones [F_BOOTEND] = REG_FIELD(FXAS21002C_REG_INT_SRC_FLAG, 3, 3),
69bfec5753SLee Jones [F_SRC_FIFO] = REG_FIELD(FXAS21002C_REG_INT_SRC_FLAG, 2, 2),
70bfec5753SLee Jones [F_SRC_RT] = REG_FIELD(FXAS21002C_REG_INT_SRC_FLAG, 1, 1),
71bfec5753SLee Jones [F_SRC_DRDY] = REG_FIELD(FXAS21002C_REG_INT_SRC_FLAG, 0, 0),
72bfec5753SLee Jones [F_WHO_AM_I] = REG_FIELD(FXAS21002C_REG_WHO_AM_I, 0, 7),
73bfec5753SLee Jones [F_BW] = REG_FIELD(FXAS21002C_REG_CTRL0, 6, 7),
74bfec5753SLee Jones [F_SPIW] = REG_FIELD(FXAS21002C_REG_CTRL0, 5, 5),
75bfec5753SLee Jones [F_SEL] = REG_FIELD(FXAS21002C_REG_CTRL0, 3, 4),
76bfec5753SLee Jones [F_HPF_EN] = REG_FIELD(FXAS21002C_REG_CTRL0, 2, 2),
77bfec5753SLee Jones [F_FS] = REG_FIELD(FXAS21002C_REG_CTRL0, 0, 1),
78bfec5753SLee Jones [F_ELE] = REG_FIELD(FXAS21002C_REG_RT_CFG, 3, 3),
79bfec5753SLee Jones [F_ZTEFE] = REG_FIELD(FXAS21002C_REG_RT_CFG, 2, 2),
80bfec5753SLee Jones [F_YTEFE] = REG_FIELD(FXAS21002C_REG_RT_CFG, 1, 1),
81bfec5753SLee Jones [F_XTEFE] = REG_FIELD(FXAS21002C_REG_RT_CFG, 0, 0),
82bfec5753SLee Jones [F_EA] = REG_FIELD(FXAS21002C_REG_RT_SRC, 6, 6),
83bfec5753SLee Jones [F_ZRT] = REG_FIELD(FXAS21002C_REG_RT_SRC, 5, 5),
84bfec5753SLee Jones [F_ZRT_POL] = REG_FIELD(FXAS21002C_REG_RT_SRC, 4, 4),
85bfec5753SLee Jones [F_YRT] = REG_FIELD(FXAS21002C_REG_RT_SRC, 3, 3),
86bfec5753SLee Jones [F_YRT_POL] = REG_FIELD(FXAS21002C_REG_RT_SRC, 2, 2),
87bfec5753SLee Jones [F_XRT] = REG_FIELD(FXAS21002C_REG_RT_SRC, 1, 1),
88bfec5753SLee Jones [F_XRT_POL] = REG_FIELD(FXAS21002C_REG_RT_SRC, 0, 0),
89bfec5753SLee Jones [F_DBCNTM] = REG_FIELD(FXAS21002C_REG_RT_THS, 7, 7),
90bfec5753SLee Jones [F_THS] = REG_FIELD(FXAS21002C_REG_RT_SRC, 0, 6),
91bfec5753SLee Jones [F_RT_COUNT] = REG_FIELD(FXAS21002C_REG_RT_COUNT, 0, 7),
92bfec5753SLee Jones [F_TEMP] = REG_FIELD(FXAS21002C_REG_TEMP, 0, 7),
93bfec5753SLee Jones [F_RST] = REG_FIELD(FXAS21002C_REG_CTRL1, 6, 6),
94bfec5753SLee Jones [F_ST] = REG_FIELD(FXAS21002C_REG_CTRL1, 5, 5),
95bfec5753SLee Jones [F_DR] = REG_FIELD(FXAS21002C_REG_CTRL1, 2, 4),
96bfec5753SLee Jones [F_ACTIVE] = REG_FIELD(FXAS21002C_REG_CTRL1, 1, 1),
97bfec5753SLee Jones [F_READY] = REG_FIELD(FXAS21002C_REG_CTRL1, 0, 0),
98bfec5753SLee Jones [F_INT_CFG_FIFO] = REG_FIELD(FXAS21002C_REG_CTRL2, 7, 7),
99bfec5753SLee Jones [F_INT_EN_FIFO] = REG_FIELD(FXAS21002C_REG_CTRL2, 6, 6),
100bfec5753SLee Jones [F_INT_CFG_RT] = REG_FIELD(FXAS21002C_REG_CTRL2, 5, 5),
101bfec5753SLee Jones [F_INT_EN_RT] = REG_FIELD(FXAS21002C_REG_CTRL2, 4, 4),
102bfec5753SLee Jones [F_INT_CFG_DRDY] = REG_FIELD(FXAS21002C_REG_CTRL2, 3, 3),
103bfec5753SLee Jones [F_INT_EN_DRDY] = REG_FIELD(FXAS21002C_REG_CTRL2, 2, 2),
104bfec5753SLee Jones [F_IPOL] = REG_FIELD(FXAS21002C_REG_CTRL2, 1, 1),
105bfec5753SLee Jones [F_PP_OD] = REG_FIELD(FXAS21002C_REG_CTRL2, 0, 0),
106bfec5753SLee Jones [F_WRAPTOONE] = REG_FIELD(FXAS21002C_REG_CTRL3, 3, 3),
107bfec5753SLee Jones [F_EXTCTRLEN] = REG_FIELD(FXAS21002C_REG_CTRL3, 2, 2),
108bfec5753SLee Jones [F_FS_DOUBLE] = REG_FIELD(FXAS21002C_REG_CTRL3, 0, 0),
109bfec5753SLee Jones };
110bfec5753SLee Jones
111a0701b62SRui Miguel Silva static const int fxas21002c_odr_values[] = {
112a0701b62SRui Miguel Silva 800, 400, 200, 100, 50, 25, 12, 12
113a0701b62SRui Miguel Silva };
114a0701b62SRui Miguel Silva
115a0701b62SRui Miguel Silva /*
116a0701b62SRui Miguel Silva * These values are taken from the low-pass filter cutoff frequency calculated
117a0701b62SRui Miguel Silva * ODR * 0.lpf_values. So, for ODR = 800Hz with a lpf value = 0.32
118a0701b62SRui Miguel Silva * => LPF cutoff frequency = 800 * 0.32 = 256 Hz
119a0701b62SRui Miguel Silva */
120a0701b62SRui Miguel Silva static const int fxas21002c_lpf_values[] = {
121a0701b62SRui Miguel Silva 32, 16, 8
122a0701b62SRui Miguel Silva };
123a0701b62SRui Miguel Silva
124a0701b62SRui Miguel Silva /*
125a0701b62SRui Miguel Silva * These values are taken from the high-pass filter cutoff frequency calculated
126a0701b62SRui Miguel Silva * ODR * 0.0hpf_values. So, for ODR = 800Hz with a hpf value = 0.018750
127a0701b62SRui Miguel Silva * => HPF cutoff frequency = 800 * 0.018750 = 15 Hz
128a0701b62SRui Miguel Silva */
129a0701b62SRui Miguel Silva static const int fxas21002c_hpf_values[] = {
130a0701b62SRui Miguel Silva 18750, 9625, 4875, 2475
131a0701b62SRui Miguel Silva };
132a0701b62SRui Miguel Silva
133a0701b62SRui Miguel Silva static const int fxas21002c_range_values[] = {
134a0701b62SRui Miguel Silva 4000, 2000, 1000, 500, 250
135a0701b62SRui Miguel Silva };
136a0701b62SRui Miguel Silva
137a0701b62SRui Miguel Silva struct fxas21002c_data {
138a0701b62SRui Miguel Silva u8 chip_id;
139a0701b62SRui Miguel Silva enum fxas21002c_mode_state mode;
140a0701b62SRui Miguel Silva enum fxas21002c_mode_state prev_mode;
141a0701b62SRui Miguel Silva
142a0701b62SRui Miguel Silva struct mutex lock; /* serialize data access */
143a0701b62SRui Miguel Silva struct regmap *regmap;
144a0701b62SRui Miguel Silva struct regmap_field *regmap_fields[F_MAX_FIELDS];
145a0701b62SRui Miguel Silva struct iio_trigger *dready_trig;
146a0701b62SRui Miguel Silva s64 timestamp;
147a0701b62SRui Miguel Silva int irq;
148a0701b62SRui Miguel Silva
149a0701b62SRui Miguel Silva struct regulator *vdd;
150a0701b62SRui Miguel Silva struct regulator *vddio;
151a0701b62SRui Miguel Silva
152a0701b62SRui Miguel Silva /*
1533aafe923SJonathan Cameron * DMA (thus cache coherency maintenance) may require the
1543aafe923SJonathan Cameron * transfer buffers live in their own cache lines.
155a0701b62SRui Miguel Silva */
1563aafe923SJonathan Cameron s16 buffer[8] __aligned(IIO_DMA_MINALIGN);
157a0701b62SRui Miguel Silva };
158a0701b62SRui Miguel Silva
159a0701b62SRui Miguel Silva enum fxas21002c_channel_index {
160a0701b62SRui Miguel Silva CHANNEL_SCAN_INDEX_X,
161a0701b62SRui Miguel Silva CHANNEL_SCAN_INDEX_Y,
162a0701b62SRui Miguel Silva CHANNEL_SCAN_INDEX_Z,
163a0701b62SRui Miguel Silva CHANNEL_SCAN_MAX,
164a0701b62SRui Miguel Silva };
165a0701b62SRui Miguel Silva
fxas21002c_odr_hz_from_value(struct fxas21002c_data * data,u8 value)166a0701b62SRui Miguel Silva static int fxas21002c_odr_hz_from_value(struct fxas21002c_data *data, u8 value)
167a0701b62SRui Miguel Silva {
168a0701b62SRui Miguel Silva int odr_value_max = ARRAY_SIZE(fxas21002c_odr_values) - 1;
169a0701b62SRui Miguel Silva
170a0701b62SRui Miguel Silva value = min_t(u8, value, odr_value_max);
171a0701b62SRui Miguel Silva
172a0701b62SRui Miguel Silva return fxas21002c_odr_values[value];
173a0701b62SRui Miguel Silva }
174a0701b62SRui Miguel Silva
fxas21002c_odr_value_from_hz(struct fxas21002c_data * data,unsigned int hz)175a0701b62SRui Miguel Silva static int fxas21002c_odr_value_from_hz(struct fxas21002c_data *data,
176a0701b62SRui Miguel Silva unsigned int hz)
177a0701b62SRui Miguel Silva {
178a0701b62SRui Miguel Silva int odr_table_size = ARRAY_SIZE(fxas21002c_odr_values);
179a0701b62SRui Miguel Silva int i;
180a0701b62SRui Miguel Silva
181a0701b62SRui Miguel Silva for (i = 0; i < odr_table_size; i++)
182a0701b62SRui Miguel Silva if (fxas21002c_odr_values[i] == hz)
183a0701b62SRui Miguel Silva return i;
184a0701b62SRui Miguel Silva
185a0701b62SRui Miguel Silva return -EINVAL;
186a0701b62SRui Miguel Silva }
187a0701b62SRui Miguel Silva
fxas21002c_lpf_bw_from_value(struct fxas21002c_data * data,u8 value)188a0701b62SRui Miguel Silva static int fxas21002c_lpf_bw_from_value(struct fxas21002c_data *data, u8 value)
189a0701b62SRui Miguel Silva {
190a0701b62SRui Miguel Silva int lpf_value_max = ARRAY_SIZE(fxas21002c_lpf_values) - 1;
191a0701b62SRui Miguel Silva
192a0701b62SRui Miguel Silva value = min_t(u8, value, lpf_value_max);
193a0701b62SRui Miguel Silva
194a0701b62SRui Miguel Silva return fxas21002c_lpf_values[value];
195a0701b62SRui Miguel Silva }
196a0701b62SRui Miguel Silva
fxas21002c_lpf_value_from_bw(struct fxas21002c_data * data,unsigned int hz)197a0701b62SRui Miguel Silva static int fxas21002c_lpf_value_from_bw(struct fxas21002c_data *data,
198a0701b62SRui Miguel Silva unsigned int hz)
199a0701b62SRui Miguel Silva {
200a0701b62SRui Miguel Silva int lpf_table_size = ARRAY_SIZE(fxas21002c_lpf_values);
201a0701b62SRui Miguel Silva int i;
202a0701b62SRui Miguel Silva
203a0701b62SRui Miguel Silva for (i = 0; i < lpf_table_size; i++)
204a0701b62SRui Miguel Silva if (fxas21002c_lpf_values[i] == hz)
205a0701b62SRui Miguel Silva return i;
206a0701b62SRui Miguel Silva
207a0701b62SRui Miguel Silva return -EINVAL;
208a0701b62SRui Miguel Silva }
209a0701b62SRui Miguel Silva
fxas21002c_hpf_sel_from_value(struct fxas21002c_data * data,u8 value)210a0701b62SRui Miguel Silva static int fxas21002c_hpf_sel_from_value(struct fxas21002c_data *data, u8 value)
211a0701b62SRui Miguel Silva {
212a0701b62SRui Miguel Silva int hpf_value_max = ARRAY_SIZE(fxas21002c_hpf_values) - 1;
213a0701b62SRui Miguel Silva
214a0701b62SRui Miguel Silva value = min_t(u8, value, hpf_value_max);
215a0701b62SRui Miguel Silva
216a0701b62SRui Miguel Silva return fxas21002c_hpf_values[value];
217a0701b62SRui Miguel Silva }
218a0701b62SRui Miguel Silva
fxas21002c_hpf_value_from_sel(struct fxas21002c_data * data,unsigned int hz)219a0701b62SRui Miguel Silva static int fxas21002c_hpf_value_from_sel(struct fxas21002c_data *data,
220a0701b62SRui Miguel Silva unsigned int hz)
221a0701b62SRui Miguel Silva {
222a0701b62SRui Miguel Silva int hpf_table_size = ARRAY_SIZE(fxas21002c_hpf_values);
223a0701b62SRui Miguel Silva int i;
224a0701b62SRui Miguel Silva
225a0701b62SRui Miguel Silva for (i = 0; i < hpf_table_size; i++)
226a0701b62SRui Miguel Silva if (fxas21002c_hpf_values[i] == hz)
227a0701b62SRui Miguel Silva return i;
228a0701b62SRui Miguel Silva
229a0701b62SRui Miguel Silva return -EINVAL;
230a0701b62SRui Miguel Silva }
231a0701b62SRui Miguel Silva
fxas21002c_range_fs_from_value(struct fxas21002c_data * data,u8 value)232a0701b62SRui Miguel Silva static int fxas21002c_range_fs_from_value(struct fxas21002c_data *data,
233a0701b62SRui Miguel Silva u8 value)
234a0701b62SRui Miguel Silva {
235a0701b62SRui Miguel Silva int range_value_max = ARRAY_SIZE(fxas21002c_range_values) - 1;
236a0701b62SRui Miguel Silva unsigned int fs_double;
237a0701b62SRui Miguel Silva int ret;
238a0701b62SRui Miguel Silva
239a0701b62SRui Miguel Silva /* We need to check if FS_DOUBLE is enabled to offset the value */
240a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_FS_DOUBLE], &fs_double);
241a0701b62SRui Miguel Silva if (ret < 0)
242a0701b62SRui Miguel Silva return ret;
243a0701b62SRui Miguel Silva
244a0701b62SRui Miguel Silva if (!fs_double)
245a0701b62SRui Miguel Silva value += 1;
246a0701b62SRui Miguel Silva
247a0701b62SRui Miguel Silva value = min_t(u8, value, range_value_max);
248a0701b62SRui Miguel Silva
249a0701b62SRui Miguel Silva return fxas21002c_range_values[value];
250a0701b62SRui Miguel Silva }
251a0701b62SRui Miguel Silva
fxas21002c_range_value_from_fs(struct fxas21002c_data * data,unsigned int range)252a0701b62SRui Miguel Silva static int fxas21002c_range_value_from_fs(struct fxas21002c_data *data,
253a0701b62SRui Miguel Silva unsigned int range)
254a0701b62SRui Miguel Silva {
255a0701b62SRui Miguel Silva int range_table_size = ARRAY_SIZE(fxas21002c_range_values);
256a0701b62SRui Miguel Silva bool found = false;
257a0701b62SRui Miguel Silva int fs_double = 0;
258a0701b62SRui Miguel Silva int ret;
259a0701b62SRui Miguel Silva int i;
260a0701b62SRui Miguel Silva
261a0701b62SRui Miguel Silva for (i = 0; i < range_table_size; i++)
262a0701b62SRui Miguel Silva if (fxas21002c_range_values[i] == range) {
263a0701b62SRui Miguel Silva found = true;
264a0701b62SRui Miguel Silva break;
265a0701b62SRui Miguel Silva }
266a0701b62SRui Miguel Silva
267a0701b62SRui Miguel Silva if (!found)
268a0701b62SRui Miguel Silva return -EINVAL;
269a0701b62SRui Miguel Silva
270a0701b62SRui Miguel Silva if (range > FXAS21002C_RANGE_LIMIT_DOUBLE)
271a0701b62SRui Miguel Silva fs_double = 1;
272a0701b62SRui Miguel Silva
273a0701b62SRui Miguel Silva ret = regmap_field_write(data->regmap_fields[F_FS_DOUBLE], fs_double);
274a0701b62SRui Miguel Silva if (ret < 0)
275a0701b62SRui Miguel Silva return ret;
276a0701b62SRui Miguel Silva
277a0701b62SRui Miguel Silva return i;
278a0701b62SRui Miguel Silva }
279a0701b62SRui Miguel Silva
fxas21002c_mode_get(struct fxas21002c_data * data)280a0701b62SRui Miguel Silva static int fxas21002c_mode_get(struct fxas21002c_data *data)
281a0701b62SRui Miguel Silva {
282a0701b62SRui Miguel Silva unsigned int active;
283a0701b62SRui Miguel Silva unsigned int ready;
284a0701b62SRui Miguel Silva int ret;
285a0701b62SRui Miguel Silva
286a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_ACTIVE], &active);
287a0701b62SRui Miguel Silva if (ret < 0)
288a0701b62SRui Miguel Silva return ret;
289a0701b62SRui Miguel Silva if (active)
290a0701b62SRui Miguel Silva return FXAS21002C_MODE_ACTIVE;
291a0701b62SRui Miguel Silva
292a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_READY], &ready);
293a0701b62SRui Miguel Silva if (ret < 0)
294a0701b62SRui Miguel Silva return ret;
295a0701b62SRui Miguel Silva if (ready)
296a0701b62SRui Miguel Silva return FXAS21002C_MODE_READY;
297a0701b62SRui Miguel Silva
298a0701b62SRui Miguel Silva return FXAS21002C_MODE_STANDBY;
299a0701b62SRui Miguel Silva }
300a0701b62SRui Miguel Silva
fxas21002c_mode_set(struct fxas21002c_data * data,enum fxas21002c_mode_state mode)301a0701b62SRui Miguel Silva static int fxas21002c_mode_set(struct fxas21002c_data *data,
302a0701b62SRui Miguel Silva enum fxas21002c_mode_state mode)
303a0701b62SRui Miguel Silva {
304a0701b62SRui Miguel Silva int ret;
305a0701b62SRui Miguel Silva
306a0701b62SRui Miguel Silva if (mode == data->mode)
307a0701b62SRui Miguel Silva return 0;
308a0701b62SRui Miguel Silva
309a0701b62SRui Miguel Silva if (mode == FXAS21002C_MODE_READY)
310a0701b62SRui Miguel Silva ret = regmap_field_write(data->regmap_fields[F_READY], 1);
311a0701b62SRui Miguel Silva else
312a0701b62SRui Miguel Silva ret = regmap_field_write(data->regmap_fields[F_READY], 0);
313a0701b62SRui Miguel Silva if (ret < 0)
314a0701b62SRui Miguel Silva return ret;
315a0701b62SRui Miguel Silva
316a0701b62SRui Miguel Silva if (mode == FXAS21002C_MODE_ACTIVE)
317a0701b62SRui Miguel Silva ret = regmap_field_write(data->regmap_fields[F_ACTIVE], 1);
318a0701b62SRui Miguel Silva else
319a0701b62SRui Miguel Silva ret = regmap_field_write(data->regmap_fields[F_ACTIVE], 0);
320a0701b62SRui Miguel Silva if (ret < 0)
321a0701b62SRui Miguel Silva return ret;
322a0701b62SRui Miguel Silva
323a0701b62SRui Miguel Silva /* if going to active wait the setup times */
324a0701b62SRui Miguel Silva if (mode == FXAS21002C_MODE_ACTIVE &&
325a0701b62SRui Miguel Silva data->mode == FXAS21002C_MODE_STANDBY)
326a0701b62SRui Miguel Silva msleep_interruptible(FXAS21002C_STANDBY_ACTIVE_TIME_MS);
327a0701b62SRui Miguel Silva
328a0701b62SRui Miguel Silva if (data->mode == FXAS21002C_MODE_READY)
329a0701b62SRui Miguel Silva msleep_interruptible(FXAS21002C_READY_ACTIVE_TIME_MS);
330a0701b62SRui Miguel Silva
331a0701b62SRui Miguel Silva data->prev_mode = data->mode;
332a0701b62SRui Miguel Silva data->mode = mode;
333a0701b62SRui Miguel Silva
334a0701b62SRui Miguel Silva return ret;
335a0701b62SRui Miguel Silva }
336a0701b62SRui Miguel Silva
fxas21002c_write(struct fxas21002c_data * data,enum fxas21002c_fields field,int bits)337a0701b62SRui Miguel Silva static int fxas21002c_write(struct fxas21002c_data *data,
338a0701b62SRui Miguel Silva enum fxas21002c_fields field, int bits)
339a0701b62SRui Miguel Silva {
340a0701b62SRui Miguel Silva int actual_mode;
341a0701b62SRui Miguel Silva int ret;
342a0701b62SRui Miguel Silva
343a0701b62SRui Miguel Silva mutex_lock(&data->lock);
344a0701b62SRui Miguel Silva
345a0701b62SRui Miguel Silva actual_mode = fxas21002c_mode_get(data);
346a0701b62SRui Miguel Silva if (actual_mode < 0) {
347a0701b62SRui Miguel Silva ret = actual_mode;
348a0701b62SRui Miguel Silva goto out_unlock;
349a0701b62SRui Miguel Silva }
350a0701b62SRui Miguel Silva
351a0701b62SRui Miguel Silva ret = fxas21002c_mode_set(data, FXAS21002C_MODE_READY);
352a0701b62SRui Miguel Silva if (ret < 0)
353a0701b62SRui Miguel Silva goto out_unlock;
354a0701b62SRui Miguel Silva
355a0701b62SRui Miguel Silva ret = regmap_field_write(data->regmap_fields[field], bits);
356a0701b62SRui Miguel Silva if (ret < 0)
357a0701b62SRui Miguel Silva goto out_unlock;
358a0701b62SRui Miguel Silva
359a0701b62SRui Miguel Silva ret = fxas21002c_mode_set(data, data->prev_mode);
360a0701b62SRui Miguel Silva
361a0701b62SRui Miguel Silva out_unlock:
362a0701b62SRui Miguel Silva mutex_unlock(&data->lock);
363a0701b62SRui Miguel Silva
364a0701b62SRui Miguel Silva return ret;
365a0701b62SRui Miguel Silva }
366a0701b62SRui Miguel Silva
fxas21002c_pm_get(struct fxas21002c_data * data)367a0701b62SRui Miguel Silva static int fxas21002c_pm_get(struct fxas21002c_data *data)
368a0701b62SRui Miguel Silva {
36941120ebbSJonathan Cameron return pm_runtime_resume_and_get(regmap_get_device(data->regmap));
370a0701b62SRui Miguel Silva }
371a0701b62SRui Miguel Silva
fxas21002c_pm_put(struct fxas21002c_data * data)372a0701b62SRui Miguel Silva static int fxas21002c_pm_put(struct fxas21002c_data *data)
373a0701b62SRui Miguel Silva {
374a0701b62SRui Miguel Silva struct device *dev = regmap_get_device(data->regmap);
375a0701b62SRui Miguel Silva
376a0701b62SRui Miguel Silva pm_runtime_mark_last_busy(dev);
377a0701b62SRui Miguel Silva
378a0701b62SRui Miguel Silva return pm_runtime_put_autosuspend(dev);
379a0701b62SRui Miguel Silva }
380a0701b62SRui Miguel Silva
fxas21002c_temp_get(struct fxas21002c_data * data,int * val)381a0701b62SRui Miguel Silva static int fxas21002c_temp_get(struct fxas21002c_data *data, int *val)
382a0701b62SRui Miguel Silva {
383a0701b62SRui Miguel Silva struct device *dev = regmap_get_device(data->regmap);
384a0701b62SRui Miguel Silva unsigned int temp;
385a0701b62SRui Miguel Silva int ret;
386a0701b62SRui Miguel Silva
387a0701b62SRui Miguel Silva mutex_lock(&data->lock);
388a0701b62SRui Miguel Silva ret = fxas21002c_pm_get(data);
389a0701b62SRui Miguel Silva if (ret < 0)
390a0701b62SRui Miguel Silva goto data_unlock;
391a0701b62SRui Miguel Silva
392a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_TEMP], &temp);
393a0701b62SRui Miguel Silva if (ret < 0) {
394a0701b62SRui Miguel Silva dev_err(dev, "failed to read temp: %d\n", ret);
3952a54c8c9SRui Miguel Silva fxas21002c_pm_put(data);
396a0701b62SRui Miguel Silva goto data_unlock;
397a0701b62SRui Miguel Silva }
398a0701b62SRui Miguel Silva
399a0701b62SRui Miguel Silva *val = sign_extend32(temp, 7);
400a0701b62SRui Miguel Silva
401a0701b62SRui Miguel Silva ret = fxas21002c_pm_put(data);
402a0701b62SRui Miguel Silva if (ret < 0)
403a0701b62SRui Miguel Silva goto data_unlock;
404a0701b62SRui Miguel Silva
405a0701b62SRui Miguel Silva ret = IIO_VAL_INT;
406a0701b62SRui Miguel Silva
407a0701b62SRui Miguel Silva data_unlock:
408a0701b62SRui Miguel Silva mutex_unlock(&data->lock);
409a0701b62SRui Miguel Silva
410a0701b62SRui Miguel Silva return ret;
411a0701b62SRui Miguel Silva }
412a0701b62SRui Miguel Silva
fxas21002c_axis_get(struct fxas21002c_data * data,int index,int * val)413a0701b62SRui Miguel Silva static int fxas21002c_axis_get(struct fxas21002c_data *data,
414a0701b62SRui Miguel Silva int index, int *val)
415a0701b62SRui Miguel Silva {
416a0701b62SRui Miguel Silva struct device *dev = regmap_get_device(data->regmap);
417a0701b62SRui Miguel Silva __be16 axis_be;
418a0701b62SRui Miguel Silva int ret;
419a0701b62SRui Miguel Silva
420a0701b62SRui Miguel Silva mutex_lock(&data->lock);
421a0701b62SRui Miguel Silva ret = fxas21002c_pm_get(data);
422a0701b62SRui Miguel Silva if (ret < 0)
423a0701b62SRui Miguel Silva goto data_unlock;
424a0701b62SRui Miguel Silva
425a0701b62SRui Miguel Silva ret = regmap_bulk_read(data->regmap, FXAS21002C_AXIS_TO_REG(index),
426a0701b62SRui Miguel Silva &axis_be, sizeof(axis_be));
427a0701b62SRui Miguel Silva if (ret < 0) {
428a0701b62SRui Miguel Silva dev_err(dev, "failed to read axis: %d: %d\n", index, ret);
4292a54c8c9SRui Miguel Silva fxas21002c_pm_put(data);
430a0701b62SRui Miguel Silva goto data_unlock;
431a0701b62SRui Miguel Silva }
432a0701b62SRui Miguel Silva
433a0701b62SRui Miguel Silva *val = sign_extend32(be16_to_cpu(axis_be), 15);
434a0701b62SRui Miguel Silva
435a0701b62SRui Miguel Silva ret = fxas21002c_pm_put(data);
436a0701b62SRui Miguel Silva if (ret < 0)
437a0701b62SRui Miguel Silva goto data_unlock;
438a0701b62SRui Miguel Silva
439a0701b62SRui Miguel Silva ret = IIO_VAL_INT;
440a0701b62SRui Miguel Silva
441a0701b62SRui Miguel Silva data_unlock:
442a0701b62SRui Miguel Silva mutex_unlock(&data->lock);
443a0701b62SRui Miguel Silva
444a0701b62SRui Miguel Silva return ret;
445a0701b62SRui Miguel Silva }
446a0701b62SRui Miguel Silva
fxas21002c_odr_get(struct fxas21002c_data * data,int * odr)447a0701b62SRui Miguel Silva static int fxas21002c_odr_get(struct fxas21002c_data *data, int *odr)
448a0701b62SRui Miguel Silva {
449a0701b62SRui Miguel Silva unsigned int odr_bits;
450a0701b62SRui Miguel Silva int ret;
451a0701b62SRui Miguel Silva
452a0701b62SRui Miguel Silva mutex_lock(&data->lock);
453a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_DR], &odr_bits);
454a0701b62SRui Miguel Silva if (ret < 0)
455a0701b62SRui Miguel Silva goto data_unlock;
456a0701b62SRui Miguel Silva
457a0701b62SRui Miguel Silva *odr = fxas21002c_odr_hz_from_value(data, odr_bits);
458a0701b62SRui Miguel Silva
459a0701b62SRui Miguel Silva ret = IIO_VAL_INT;
460a0701b62SRui Miguel Silva
461a0701b62SRui Miguel Silva data_unlock:
462a0701b62SRui Miguel Silva mutex_unlock(&data->lock);
463a0701b62SRui Miguel Silva
464a0701b62SRui Miguel Silva return ret;
465a0701b62SRui Miguel Silva }
466a0701b62SRui Miguel Silva
fxas21002c_odr_set(struct fxas21002c_data * data,int odr)467a0701b62SRui Miguel Silva static int fxas21002c_odr_set(struct fxas21002c_data *data, int odr)
468a0701b62SRui Miguel Silva {
469a0701b62SRui Miguel Silva int odr_bits;
470a0701b62SRui Miguel Silva
471a0701b62SRui Miguel Silva odr_bits = fxas21002c_odr_value_from_hz(data, odr);
472a0701b62SRui Miguel Silva if (odr_bits < 0)
473a0701b62SRui Miguel Silva return odr_bits;
474a0701b62SRui Miguel Silva
475a0701b62SRui Miguel Silva return fxas21002c_write(data, F_DR, odr_bits);
476a0701b62SRui Miguel Silva }
477a0701b62SRui Miguel Silva
fxas21002c_lpf_get(struct fxas21002c_data * data,int * val2)478a0701b62SRui Miguel Silva static int fxas21002c_lpf_get(struct fxas21002c_data *data, int *val2)
479a0701b62SRui Miguel Silva {
480a0701b62SRui Miguel Silva unsigned int bw_bits;
481a0701b62SRui Miguel Silva int ret;
482a0701b62SRui Miguel Silva
483a0701b62SRui Miguel Silva mutex_lock(&data->lock);
484a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_BW], &bw_bits);
485a0701b62SRui Miguel Silva if (ret < 0)
486a0701b62SRui Miguel Silva goto data_unlock;
487a0701b62SRui Miguel Silva
488a0701b62SRui Miguel Silva *val2 = fxas21002c_lpf_bw_from_value(data, bw_bits) * 10000;
489a0701b62SRui Miguel Silva
490a0701b62SRui Miguel Silva ret = IIO_VAL_INT_PLUS_MICRO;
491a0701b62SRui Miguel Silva
492a0701b62SRui Miguel Silva data_unlock:
493a0701b62SRui Miguel Silva mutex_unlock(&data->lock);
494a0701b62SRui Miguel Silva
495a0701b62SRui Miguel Silva return ret;
496a0701b62SRui Miguel Silva }
497a0701b62SRui Miguel Silva
fxas21002c_lpf_set(struct fxas21002c_data * data,int bw)498a0701b62SRui Miguel Silva static int fxas21002c_lpf_set(struct fxas21002c_data *data, int bw)
499a0701b62SRui Miguel Silva {
500a0701b62SRui Miguel Silva int bw_bits;
501a0701b62SRui Miguel Silva int odr;
502a0701b62SRui Miguel Silva int ret;
503a0701b62SRui Miguel Silva
504a0701b62SRui Miguel Silva bw_bits = fxas21002c_lpf_value_from_bw(data, bw);
505a0701b62SRui Miguel Silva if (bw_bits < 0)
506a0701b62SRui Miguel Silva return bw_bits;
507a0701b62SRui Miguel Silva
508a0701b62SRui Miguel Silva /*
509a0701b62SRui Miguel Silva * From table 33 of the device spec, for ODR = 25Hz and 12.5 value 0.08
510a0701b62SRui Miguel Silva * is not allowed and for ODR = 12.5 value 0.16 is also not allowed
511a0701b62SRui Miguel Silva */
512a0701b62SRui Miguel Silva ret = fxas21002c_odr_get(data, &odr);
513a0701b62SRui Miguel Silva if (ret < 0)
514a0701b62SRui Miguel Silva return -EINVAL;
515a0701b62SRui Miguel Silva
516a0701b62SRui Miguel Silva if ((odr == 25 && bw_bits > 0x01) || (odr == 12 && bw_bits > 0))
517a0701b62SRui Miguel Silva return -EINVAL;
518a0701b62SRui Miguel Silva
519a0701b62SRui Miguel Silva return fxas21002c_write(data, F_BW, bw_bits);
520a0701b62SRui Miguel Silva }
521a0701b62SRui Miguel Silva
fxas21002c_hpf_get(struct fxas21002c_data * data,int * val2)522a0701b62SRui Miguel Silva static int fxas21002c_hpf_get(struct fxas21002c_data *data, int *val2)
523a0701b62SRui Miguel Silva {
524a0701b62SRui Miguel Silva unsigned int sel_bits;
525a0701b62SRui Miguel Silva int ret;
526a0701b62SRui Miguel Silva
527a0701b62SRui Miguel Silva mutex_lock(&data->lock);
528a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_SEL], &sel_bits);
529a0701b62SRui Miguel Silva if (ret < 0)
530a0701b62SRui Miguel Silva goto data_unlock;
531a0701b62SRui Miguel Silva
532a0701b62SRui Miguel Silva *val2 = fxas21002c_hpf_sel_from_value(data, sel_bits);
533a0701b62SRui Miguel Silva
534a0701b62SRui Miguel Silva ret = IIO_VAL_INT_PLUS_MICRO;
535a0701b62SRui Miguel Silva
536a0701b62SRui Miguel Silva data_unlock:
537a0701b62SRui Miguel Silva mutex_unlock(&data->lock);
538a0701b62SRui Miguel Silva
539a0701b62SRui Miguel Silva return ret;
540a0701b62SRui Miguel Silva }
541a0701b62SRui Miguel Silva
fxas21002c_hpf_set(struct fxas21002c_data * data,int sel)542a0701b62SRui Miguel Silva static int fxas21002c_hpf_set(struct fxas21002c_data *data, int sel)
543a0701b62SRui Miguel Silva {
544a0701b62SRui Miguel Silva int sel_bits;
545a0701b62SRui Miguel Silva
546a0701b62SRui Miguel Silva sel_bits = fxas21002c_hpf_value_from_sel(data, sel);
547a0701b62SRui Miguel Silva if (sel_bits < 0)
548a0701b62SRui Miguel Silva return sel_bits;
549a0701b62SRui Miguel Silva
550a0701b62SRui Miguel Silva return fxas21002c_write(data, F_SEL, sel_bits);
551a0701b62SRui Miguel Silva }
552a0701b62SRui Miguel Silva
fxas21002c_scale_get(struct fxas21002c_data * data,int * val)553a0701b62SRui Miguel Silva static int fxas21002c_scale_get(struct fxas21002c_data *data, int *val)
554a0701b62SRui Miguel Silva {
555a0701b62SRui Miguel Silva int fs_bits;
556a0701b62SRui Miguel Silva int scale;
557a0701b62SRui Miguel Silva int ret;
558a0701b62SRui Miguel Silva
559a0701b62SRui Miguel Silva mutex_lock(&data->lock);
560a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_FS], &fs_bits);
561a0701b62SRui Miguel Silva if (ret < 0)
562a0701b62SRui Miguel Silva goto data_unlock;
563a0701b62SRui Miguel Silva
564a0701b62SRui Miguel Silva scale = fxas21002c_range_fs_from_value(data, fs_bits);
565a0701b62SRui Miguel Silva if (scale < 0) {
566a0701b62SRui Miguel Silva ret = scale;
567a0701b62SRui Miguel Silva goto data_unlock;
568a0701b62SRui Miguel Silva }
569a0701b62SRui Miguel Silva
570a0701b62SRui Miguel Silva *val = scale;
571a0701b62SRui Miguel Silva
572a0701b62SRui Miguel Silva data_unlock:
573a0701b62SRui Miguel Silva mutex_unlock(&data->lock);
574a0701b62SRui Miguel Silva
575a0701b62SRui Miguel Silva return ret;
576a0701b62SRui Miguel Silva }
577a0701b62SRui Miguel Silva
fxas21002c_scale_set(struct fxas21002c_data * data,int range)578a0701b62SRui Miguel Silva static int fxas21002c_scale_set(struct fxas21002c_data *data, int range)
579a0701b62SRui Miguel Silva {
580a0701b62SRui Miguel Silva int fs_bits;
581a0701b62SRui Miguel Silva
582a0701b62SRui Miguel Silva fs_bits = fxas21002c_range_value_from_fs(data, range);
583a0701b62SRui Miguel Silva if (fs_bits < 0)
584a0701b62SRui Miguel Silva return fs_bits;
585a0701b62SRui Miguel Silva
586a0701b62SRui Miguel Silva return fxas21002c_write(data, F_FS, fs_bits);
587a0701b62SRui Miguel Silva }
588a0701b62SRui Miguel Silva
fxas21002c_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)589a0701b62SRui Miguel Silva static int fxas21002c_read_raw(struct iio_dev *indio_dev,
590a0701b62SRui Miguel Silva struct iio_chan_spec const *chan, int *val,
591a0701b62SRui Miguel Silva int *val2, long mask)
592a0701b62SRui Miguel Silva {
593a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(indio_dev);
594a0701b62SRui Miguel Silva int ret;
595a0701b62SRui Miguel Silva
596a0701b62SRui Miguel Silva switch (mask) {
597a0701b62SRui Miguel Silva case IIO_CHAN_INFO_RAW:
598a0701b62SRui Miguel Silva switch (chan->type) {
599a0701b62SRui Miguel Silva case IIO_TEMP:
600a0701b62SRui Miguel Silva return fxas21002c_temp_get(data, val);
601a0701b62SRui Miguel Silva case IIO_ANGL_VEL:
602a0701b62SRui Miguel Silva return fxas21002c_axis_get(data, chan->scan_index, val);
603a0701b62SRui Miguel Silva default:
604a0701b62SRui Miguel Silva return -EINVAL;
605a0701b62SRui Miguel Silva }
606a0701b62SRui Miguel Silva case IIO_CHAN_INFO_SCALE:
607a0701b62SRui Miguel Silva switch (chan->type) {
608a0701b62SRui Miguel Silva case IIO_ANGL_VEL:
609a0701b62SRui Miguel Silva *val2 = FXAS21002C_SCALE_FRACTIONAL;
610a0701b62SRui Miguel Silva ret = fxas21002c_scale_get(data, val);
611a0701b62SRui Miguel Silva if (ret < 0)
612a0701b62SRui Miguel Silva return ret;
613a0701b62SRui Miguel Silva
614a0701b62SRui Miguel Silva return IIO_VAL_FRACTIONAL;
615a0701b62SRui Miguel Silva default:
616a0701b62SRui Miguel Silva return -EINVAL;
617a0701b62SRui Miguel Silva }
618a0701b62SRui Miguel Silva case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
619a0701b62SRui Miguel Silva *val = 0;
620a0701b62SRui Miguel Silva return fxas21002c_lpf_get(data, val2);
621a0701b62SRui Miguel Silva case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
622a0701b62SRui Miguel Silva *val = 0;
623a0701b62SRui Miguel Silva return fxas21002c_hpf_get(data, val2);
624a0701b62SRui Miguel Silva case IIO_CHAN_INFO_SAMP_FREQ:
625a0701b62SRui Miguel Silva *val2 = 0;
626a0701b62SRui Miguel Silva return fxas21002c_odr_get(data, val);
627a0701b62SRui Miguel Silva default:
628a0701b62SRui Miguel Silva return -EINVAL;
629a0701b62SRui Miguel Silva }
630a0701b62SRui Miguel Silva }
631a0701b62SRui Miguel Silva
fxas21002c_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)632a0701b62SRui Miguel Silva static int fxas21002c_write_raw(struct iio_dev *indio_dev,
633a0701b62SRui Miguel Silva struct iio_chan_spec const *chan, int val,
634a0701b62SRui Miguel Silva int val2, long mask)
635a0701b62SRui Miguel Silva {
636a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(indio_dev);
637a0701b62SRui Miguel Silva int range;
638a0701b62SRui Miguel Silva
639a0701b62SRui Miguel Silva switch (mask) {
640a0701b62SRui Miguel Silva case IIO_CHAN_INFO_SAMP_FREQ:
641a0701b62SRui Miguel Silva if (val2)
642a0701b62SRui Miguel Silva return -EINVAL;
643a0701b62SRui Miguel Silva
644a0701b62SRui Miguel Silva return fxas21002c_odr_set(data, val);
645a0701b62SRui Miguel Silva case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
646a0701b62SRui Miguel Silva if (val)
647a0701b62SRui Miguel Silva return -EINVAL;
648a0701b62SRui Miguel Silva
649a0701b62SRui Miguel Silva val2 = val2 / 10000;
650a0701b62SRui Miguel Silva return fxas21002c_lpf_set(data, val2);
651a0701b62SRui Miguel Silva case IIO_CHAN_INFO_SCALE:
652a0701b62SRui Miguel Silva switch (chan->type) {
653a0701b62SRui Miguel Silva case IIO_ANGL_VEL:
654a0701b62SRui Miguel Silva range = (((val * 1000 + val2 / 1000) *
655a0701b62SRui Miguel Silva FXAS21002C_SCALE_FRACTIONAL) / 1000);
656a0701b62SRui Miguel Silva return fxas21002c_scale_set(data, range);
657a0701b62SRui Miguel Silva default:
658a0701b62SRui Miguel Silva return -EINVAL;
659a0701b62SRui Miguel Silva }
660a0701b62SRui Miguel Silva case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
661a0701b62SRui Miguel Silva return fxas21002c_hpf_set(data, val2);
662a0701b62SRui Miguel Silva default:
663a0701b62SRui Miguel Silva return -EINVAL;
664a0701b62SRui Miguel Silva }
665a0701b62SRui Miguel Silva }
666a0701b62SRui Miguel Silva
667a0701b62SRui Miguel Silva static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("12.5 25 50 100 200 400 800");
668a0701b62SRui Miguel Silva
669a0701b62SRui Miguel Silva static IIO_CONST_ATTR(in_anglvel_filter_low_pass_3db_frequency_available,
670a0701b62SRui Miguel Silva "0.32 0.16 0.08");
671a0701b62SRui Miguel Silva
672a0701b62SRui Miguel Silva static IIO_CONST_ATTR(in_anglvel_filter_high_pass_3db_frequency_available,
673a0701b62SRui Miguel Silva "0.018750 0.009625 0.004875 0.002475");
674a0701b62SRui Miguel Silva
675a0701b62SRui Miguel Silva static IIO_CONST_ATTR(in_anglvel_scale_available,
676a0701b62SRui Miguel Silva "125.0 62.5 31.25 15.625 7.8125");
677a0701b62SRui Miguel Silva
678a0701b62SRui Miguel Silva static struct attribute *fxas21002c_attributes[] = {
679a0701b62SRui Miguel Silva &iio_const_attr_sampling_frequency_available.dev_attr.attr,
680a0701b62SRui Miguel Silva &iio_const_attr_in_anglvel_filter_low_pass_3db_frequency_available.dev_attr.attr,
681a0701b62SRui Miguel Silva &iio_const_attr_in_anglvel_filter_high_pass_3db_frequency_available.dev_attr.attr,
682a0701b62SRui Miguel Silva &iio_const_attr_in_anglvel_scale_available.dev_attr.attr,
683a0701b62SRui Miguel Silva NULL,
684a0701b62SRui Miguel Silva };
685a0701b62SRui Miguel Silva
686a0701b62SRui Miguel Silva static const struct attribute_group fxas21002c_attrs_group = {
687a0701b62SRui Miguel Silva .attrs = fxas21002c_attributes,
688a0701b62SRui Miguel Silva };
689a0701b62SRui Miguel Silva
690a0701b62SRui Miguel Silva #define FXAS21002C_CHANNEL(_axis) { \
691a0701b62SRui Miguel Silva .type = IIO_ANGL_VEL, \
692a0701b62SRui Miguel Silva .modified = 1, \
693a0701b62SRui Miguel Silva .channel2 = IIO_MOD_##_axis, \
694a0701b62SRui Miguel Silva .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
695a0701b62SRui Miguel Silva .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
696a0701b62SRui Miguel Silva BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
697a0701b62SRui Miguel Silva BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) | \
698a0701b62SRui Miguel Silva BIT(IIO_CHAN_INFO_SAMP_FREQ), \
699a0701b62SRui Miguel Silva .scan_index = CHANNEL_SCAN_INDEX_##_axis, \
700a0701b62SRui Miguel Silva .scan_type = { \
701a0701b62SRui Miguel Silva .sign = 's', \
702a0701b62SRui Miguel Silva .realbits = 16, \
703a0701b62SRui Miguel Silva .storagebits = 16, \
704a0701b62SRui Miguel Silva .endianness = IIO_BE, \
705a0701b62SRui Miguel Silva }, \
706a0701b62SRui Miguel Silva }
707a0701b62SRui Miguel Silva
708a0701b62SRui Miguel Silva static const struct iio_chan_spec fxas21002c_channels[] = {
709a0701b62SRui Miguel Silva {
710a0701b62SRui Miguel Silva .type = IIO_TEMP,
711a0701b62SRui Miguel Silva .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
712a0701b62SRui Miguel Silva .scan_index = -1,
713a0701b62SRui Miguel Silva },
714a0701b62SRui Miguel Silva FXAS21002C_CHANNEL(X),
715a0701b62SRui Miguel Silva FXAS21002C_CHANNEL(Y),
716a0701b62SRui Miguel Silva FXAS21002C_CHANNEL(Z),
717a0701b62SRui Miguel Silva };
718a0701b62SRui Miguel Silva
719a0701b62SRui Miguel Silva static const struct iio_info fxas21002c_info = {
720a0701b62SRui Miguel Silva .attrs = &fxas21002c_attrs_group,
721a0701b62SRui Miguel Silva .read_raw = &fxas21002c_read_raw,
722a0701b62SRui Miguel Silva .write_raw = &fxas21002c_write_raw,
723a0701b62SRui Miguel Silva };
724a0701b62SRui Miguel Silva
fxas21002c_trigger_handler(int irq,void * p)725a0701b62SRui Miguel Silva static irqreturn_t fxas21002c_trigger_handler(int irq, void *p)
726a0701b62SRui Miguel Silva {
727a0701b62SRui Miguel Silva struct iio_poll_func *pf = p;
728a0701b62SRui Miguel Silva struct iio_dev *indio_dev = pf->indio_dev;
729a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(indio_dev);
730a0701b62SRui Miguel Silva int ret;
731a0701b62SRui Miguel Silva
732a0701b62SRui Miguel Silva mutex_lock(&data->lock);
733*2df664d7SCarlos Song ret = fxas21002c_pm_get(data);
734a0701b62SRui Miguel Silva if (ret < 0)
735a0701b62SRui Miguel Silva goto out_unlock;
736a0701b62SRui Miguel Silva
737*2df664d7SCarlos Song ret = regmap_bulk_read(data->regmap, FXAS21002C_REG_OUT_X_MSB,
738*2df664d7SCarlos Song data->buffer, CHANNEL_SCAN_MAX * sizeof(s16));
739*2df664d7SCarlos Song if (ret < 0)
740*2df664d7SCarlos Song goto out_pm_put;
741*2df664d7SCarlos Song
742a0701b62SRui Miguel Silva iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
743a0701b62SRui Miguel Silva data->timestamp);
744a0701b62SRui Miguel Silva
745*2df664d7SCarlos Song out_pm_put:
746*2df664d7SCarlos Song fxas21002c_pm_put(data);
747*2df664d7SCarlos Song
748a0701b62SRui Miguel Silva out_unlock:
749a0701b62SRui Miguel Silva mutex_unlock(&data->lock);
750a0701b62SRui Miguel Silva
751a0701b62SRui Miguel Silva iio_trigger_notify_done(indio_dev->trig);
752a0701b62SRui Miguel Silva
753a0701b62SRui Miguel Silva return IRQ_HANDLED;
754a0701b62SRui Miguel Silva }
755a0701b62SRui Miguel Silva
fxas21002c_chip_init(struct fxas21002c_data * data)756a0701b62SRui Miguel Silva static int fxas21002c_chip_init(struct fxas21002c_data *data)
757a0701b62SRui Miguel Silva {
758a0701b62SRui Miguel Silva struct device *dev = regmap_get_device(data->regmap);
759a0701b62SRui Miguel Silva unsigned int chip_id;
760a0701b62SRui Miguel Silva int ret;
761a0701b62SRui Miguel Silva
762a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_WHO_AM_I], &chip_id);
763a0701b62SRui Miguel Silva if (ret < 0)
764a0701b62SRui Miguel Silva return ret;
765a0701b62SRui Miguel Silva
766a0701b62SRui Miguel Silva if (chip_id != FXAS21002C_CHIP_ID_1 &&
767a0701b62SRui Miguel Silva chip_id != FXAS21002C_CHIP_ID_2) {
768a0701b62SRui Miguel Silva dev_err(dev, "chip id 0x%02x is not supported\n", chip_id);
769a0701b62SRui Miguel Silva return -EINVAL;
770a0701b62SRui Miguel Silva }
771a0701b62SRui Miguel Silva
772a0701b62SRui Miguel Silva data->chip_id = chip_id;
773a0701b62SRui Miguel Silva
774a0701b62SRui Miguel Silva ret = fxas21002c_mode_set(data, FXAS21002C_MODE_STANDBY);
775a0701b62SRui Miguel Silva if (ret < 0)
776a0701b62SRui Miguel Silva return ret;
777a0701b62SRui Miguel Silva
778a0701b62SRui Miguel Silva /* Set ODR to 200HZ as default */
779a0701b62SRui Miguel Silva ret = fxas21002c_odr_set(data, 200);
780a0701b62SRui Miguel Silva if (ret < 0)
781a0701b62SRui Miguel Silva dev_err(dev, "failed to set ODR: %d\n", ret);
782a0701b62SRui Miguel Silva
783a0701b62SRui Miguel Silva return ret;
784a0701b62SRui Miguel Silva }
785a0701b62SRui Miguel Silva
fxas21002c_data_rdy_trigger_set_state(struct iio_trigger * trig,bool state)786a0701b62SRui Miguel Silva static int fxas21002c_data_rdy_trigger_set_state(struct iio_trigger *trig,
787a0701b62SRui Miguel Silva bool state)
788a0701b62SRui Miguel Silva {
789a0701b62SRui Miguel Silva struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
790a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(indio_dev);
791a0701b62SRui Miguel Silva
792a0701b62SRui Miguel Silva return regmap_field_write(data->regmap_fields[F_INT_EN_DRDY], state);
793a0701b62SRui Miguel Silva }
794a0701b62SRui Miguel Silva
795a0701b62SRui Miguel Silva static const struct iio_trigger_ops fxas21002c_trigger_ops = {
796a0701b62SRui Miguel Silva .set_trigger_state = &fxas21002c_data_rdy_trigger_set_state,
797a0701b62SRui Miguel Silva };
798a0701b62SRui Miguel Silva
fxas21002c_data_rdy_handler(int irq,void * private)799a0701b62SRui Miguel Silva static irqreturn_t fxas21002c_data_rdy_handler(int irq, void *private)
800a0701b62SRui Miguel Silva {
801a0701b62SRui Miguel Silva struct iio_dev *indio_dev = private;
802a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(indio_dev);
803a0701b62SRui Miguel Silva
804a0701b62SRui Miguel Silva data->timestamp = iio_get_time_ns(indio_dev);
805a0701b62SRui Miguel Silva
806a0701b62SRui Miguel Silva return IRQ_WAKE_THREAD;
807a0701b62SRui Miguel Silva }
808a0701b62SRui Miguel Silva
fxas21002c_data_rdy_thread(int irq,void * private)809a0701b62SRui Miguel Silva static irqreturn_t fxas21002c_data_rdy_thread(int irq, void *private)
810a0701b62SRui Miguel Silva {
811a0701b62SRui Miguel Silva struct iio_dev *indio_dev = private;
812a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(indio_dev);
813a0701b62SRui Miguel Silva unsigned int data_ready;
814a0701b62SRui Miguel Silva int ret;
815a0701b62SRui Miguel Silva
816a0701b62SRui Miguel Silva ret = regmap_field_read(data->regmap_fields[F_SRC_DRDY], &data_ready);
817a0701b62SRui Miguel Silva if (ret < 0)
818a0701b62SRui Miguel Silva return IRQ_NONE;
819a0701b62SRui Miguel Silva
820a0701b62SRui Miguel Silva if (!data_ready)
821a0701b62SRui Miguel Silva return IRQ_NONE;
822a0701b62SRui Miguel Silva
823f700e55eSMehdi Djait iio_trigger_poll_nested(data->dready_trig);
824a0701b62SRui Miguel Silva
825a0701b62SRui Miguel Silva return IRQ_HANDLED;
826a0701b62SRui Miguel Silva }
827a0701b62SRui Miguel Silva
fxas21002c_trigger_probe(struct fxas21002c_data * data)828a0701b62SRui Miguel Silva static int fxas21002c_trigger_probe(struct fxas21002c_data *data)
829a0701b62SRui Miguel Silva {
830a0701b62SRui Miguel Silva struct device *dev = regmap_get_device(data->regmap);
831a0701b62SRui Miguel Silva struct iio_dev *indio_dev = dev_get_drvdata(dev);
832a0701b62SRui Miguel Silva unsigned long irq_trig;
833a0701b62SRui Miguel Silva bool irq_open_drain;
834a0701b62SRui Miguel Silva int irq1;
835a0701b62SRui Miguel Silva int ret;
836a0701b62SRui Miguel Silva
837a0701b62SRui Miguel Silva if (!data->irq)
838a0701b62SRui Miguel Silva return 0;
839a0701b62SRui Miguel Silva
84061b9c4c7SAndy Shevchenko irq1 = fwnode_irq_get_byname(dev_fwnode(dev), "INT1");
841a0701b62SRui Miguel Silva if (irq1 == data->irq) {
842a0701b62SRui Miguel Silva dev_info(dev, "using interrupt line INT1\n");
843a0701b62SRui Miguel Silva ret = regmap_field_write(data->regmap_fields[F_INT_CFG_DRDY],
844a0701b62SRui Miguel Silva 1);
845a0701b62SRui Miguel Silva if (ret < 0)
846a0701b62SRui Miguel Silva return ret;
847a0701b62SRui Miguel Silva }
848a0701b62SRui Miguel Silva
849a0701b62SRui Miguel Silva dev_info(dev, "using interrupt line INT2\n");
850a0701b62SRui Miguel Silva
85161b9c4c7SAndy Shevchenko irq_open_drain = device_property_read_bool(dev, "drive-open-drain");
852a0701b62SRui Miguel Silva
853a0701b62SRui Miguel Silva data->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
854a0701b62SRui Miguel Silva indio_dev->name,
85515ea2878SJonathan Cameron iio_device_id(indio_dev));
856a0701b62SRui Miguel Silva if (!data->dready_trig)
857a0701b62SRui Miguel Silva return -ENOMEM;
858a0701b62SRui Miguel Silva
859a0701b62SRui Miguel Silva irq_trig = irqd_get_trigger_type(irq_get_irq_data(data->irq));
860a0701b62SRui Miguel Silva
861a0701b62SRui Miguel Silva if (irq_trig == IRQF_TRIGGER_RISING) {
862a0701b62SRui Miguel Silva ret = regmap_field_write(data->regmap_fields[F_IPOL], 1);
863a0701b62SRui Miguel Silva if (ret < 0)
864a0701b62SRui Miguel Silva return ret;
865a0701b62SRui Miguel Silva }
866a0701b62SRui Miguel Silva
867a0701b62SRui Miguel Silva if (irq_open_drain)
868a0701b62SRui Miguel Silva irq_trig |= IRQF_SHARED;
869a0701b62SRui Miguel Silva
870a0701b62SRui Miguel Silva ret = devm_request_threaded_irq(dev, data->irq,
871a0701b62SRui Miguel Silva fxas21002c_data_rdy_handler,
872a0701b62SRui Miguel Silva fxas21002c_data_rdy_thread,
873a0701b62SRui Miguel Silva irq_trig, "fxas21002c_data_ready",
874a0701b62SRui Miguel Silva indio_dev);
875a0701b62SRui Miguel Silva if (ret < 0)
876a0701b62SRui Miguel Silva return ret;
877a0701b62SRui Miguel Silva
878a0701b62SRui Miguel Silva data->dready_trig->ops = &fxas21002c_trigger_ops;
879a0701b62SRui Miguel Silva iio_trigger_set_drvdata(data->dready_trig, indio_dev);
880a0701b62SRui Miguel Silva
881a0701b62SRui Miguel Silva return devm_iio_trigger_register(dev, data->dready_trig);
882a0701b62SRui Miguel Silva }
883a0701b62SRui Miguel Silva
fxas21002c_power_enable(struct fxas21002c_data * data)884a0701b62SRui Miguel Silva static int fxas21002c_power_enable(struct fxas21002c_data *data)
885a0701b62SRui Miguel Silva {
886a0701b62SRui Miguel Silva int ret;
887a0701b62SRui Miguel Silva
888a0701b62SRui Miguel Silva ret = regulator_enable(data->vdd);
889a0701b62SRui Miguel Silva if (ret < 0)
890a0701b62SRui Miguel Silva return ret;
891a0701b62SRui Miguel Silva
892a0701b62SRui Miguel Silva ret = regulator_enable(data->vddio);
893a0701b62SRui Miguel Silva if (ret < 0) {
894a0701b62SRui Miguel Silva regulator_disable(data->vdd);
895a0701b62SRui Miguel Silva return ret;
896a0701b62SRui Miguel Silva }
897a0701b62SRui Miguel Silva
898a0701b62SRui Miguel Silva return 0;
899a0701b62SRui Miguel Silva }
900a0701b62SRui Miguel Silva
fxas21002c_power_disable(struct fxas21002c_data * data)901a0701b62SRui Miguel Silva static void fxas21002c_power_disable(struct fxas21002c_data *data)
902a0701b62SRui Miguel Silva {
903a0701b62SRui Miguel Silva regulator_disable(data->vdd);
904a0701b62SRui Miguel Silva regulator_disable(data->vddio);
905a0701b62SRui Miguel Silva }
906a0701b62SRui Miguel Silva
fxas21002c_power_disable_action(void * _data)907a0701b62SRui Miguel Silva static void fxas21002c_power_disable_action(void *_data)
908a0701b62SRui Miguel Silva {
909a0701b62SRui Miguel Silva struct fxas21002c_data *data = _data;
910a0701b62SRui Miguel Silva
911a0701b62SRui Miguel Silva fxas21002c_power_disable(data);
912a0701b62SRui Miguel Silva }
913a0701b62SRui Miguel Silva
fxas21002c_regulators_get(struct fxas21002c_data * data)914a0701b62SRui Miguel Silva static int fxas21002c_regulators_get(struct fxas21002c_data *data)
915a0701b62SRui Miguel Silva {
916a0701b62SRui Miguel Silva struct device *dev = regmap_get_device(data->regmap);
917a0701b62SRui Miguel Silva
918a0701b62SRui Miguel Silva data->vdd = devm_regulator_get(dev->parent, "vdd");
919a0701b62SRui Miguel Silva if (IS_ERR(data->vdd))
920a0701b62SRui Miguel Silva return PTR_ERR(data->vdd);
921a0701b62SRui Miguel Silva
922a0701b62SRui Miguel Silva data->vddio = devm_regulator_get(dev->parent, "vddio");
923a0701b62SRui Miguel Silva
924a0701b62SRui Miguel Silva return PTR_ERR_OR_ZERO(data->vddio);
925a0701b62SRui Miguel Silva }
926a0701b62SRui Miguel Silva
fxas21002c_core_probe(struct device * dev,struct regmap * regmap,int irq,const char * name)927a0701b62SRui Miguel Silva int fxas21002c_core_probe(struct device *dev, struct regmap *regmap, int irq,
928a0701b62SRui Miguel Silva const char *name)
929a0701b62SRui Miguel Silva {
930a0701b62SRui Miguel Silva struct fxas21002c_data *data;
931a0701b62SRui Miguel Silva struct iio_dev *indio_dev;
932a0701b62SRui Miguel Silva struct regmap_field *f;
933a0701b62SRui Miguel Silva int i;
934a0701b62SRui Miguel Silva int ret;
935a0701b62SRui Miguel Silva
936a0701b62SRui Miguel Silva indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
937a0701b62SRui Miguel Silva if (!indio_dev)
938a0701b62SRui Miguel Silva return -ENOMEM;
939a0701b62SRui Miguel Silva
940a0701b62SRui Miguel Silva data = iio_priv(indio_dev);
941a0701b62SRui Miguel Silva dev_set_drvdata(dev, indio_dev);
942a0701b62SRui Miguel Silva data->irq = irq;
943a0701b62SRui Miguel Silva data->regmap = regmap;
944a0701b62SRui Miguel Silva
945a0701b62SRui Miguel Silva for (i = 0; i < F_MAX_FIELDS; i++) {
946a0701b62SRui Miguel Silva f = devm_regmap_field_alloc(dev, data->regmap,
947a0701b62SRui Miguel Silva fxas21002c_reg_fields[i]);
948a0701b62SRui Miguel Silva if (IS_ERR(f))
949a0701b62SRui Miguel Silva return PTR_ERR(f);
950a0701b62SRui Miguel Silva
951a0701b62SRui Miguel Silva data->regmap_fields[i] = f;
952a0701b62SRui Miguel Silva }
953a0701b62SRui Miguel Silva
954a0701b62SRui Miguel Silva mutex_init(&data->lock);
955a0701b62SRui Miguel Silva
956a0701b62SRui Miguel Silva ret = fxas21002c_regulators_get(data);
957a0701b62SRui Miguel Silva if (ret < 0)
958a0701b62SRui Miguel Silva return ret;
959a0701b62SRui Miguel Silva
960a0701b62SRui Miguel Silva ret = fxas21002c_power_enable(data);
961a0701b62SRui Miguel Silva if (ret < 0)
962a0701b62SRui Miguel Silva return ret;
963a0701b62SRui Miguel Silva
964a0701b62SRui Miguel Silva ret = devm_add_action_or_reset(dev, fxas21002c_power_disable_action,
965a0701b62SRui Miguel Silva data);
966a0701b62SRui Miguel Silva if (ret < 0)
967a0701b62SRui Miguel Silva return ret;
968a0701b62SRui Miguel Silva
969a0701b62SRui Miguel Silva ret = fxas21002c_chip_init(data);
970a0701b62SRui Miguel Silva if (ret < 0)
971a0701b62SRui Miguel Silva return ret;
972a0701b62SRui Miguel Silva
973a0701b62SRui Miguel Silva indio_dev->channels = fxas21002c_channels;
974a0701b62SRui Miguel Silva indio_dev->num_channels = ARRAY_SIZE(fxas21002c_channels);
975a0701b62SRui Miguel Silva indio_dev->name = name;
976a0701b62SRui Miguel Silva indio_dev->modes = INDIO_DIRECT_MODE;
977a0701b62SRui Miguel Silva indio_dev->info = &fxas21002c_info;
978a0701b62SRui Miguel Silva
979a0701b62SRui Miguel Silva ret = fxas21002c_trigger_probe(data);
980a0701b62SRui Miguel Silva if (ret < 0)
981a0701b62SRui Miguel Silva return ret;
982a0701b62SRui Miguel Silva
983a0701b62SRui Miguel Silva ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
984a0701b62SRui Miguel Silva fxas21002c_trigger_handler, NULL);
985a0701b62SRui Miguel Silva if (ret < 0)
986a0701b62SRui Miguel Silva return ret;
987a0701b62SRui Miguel Silva
988a0701b62SRui Miguel Silva ret = pm_runtime_set_active(dev);
989a0701b62SRui Miguel Silva if (ret)
990a0701b62SRui Miguel Silva return ret;
991a0701b62SRui Miguel Silva
992a0701b62SRui Miguel Silva pm_runtime_enable(dev);
993a0701b62SRui Miguel Silva pm_runtime_set_autosuspend_delay(dev, 2000);
994a0701b62SRui Miguel Silva pm_runtime_use_autosuspend(dev);
995a0701b62SRui Miguel Silva
996a0701b62SRui Miguel Silva ret = iio_device_register(indio_dev);
997a0701b62SRui Miguel Silva if (ret < 0)
998a0701b62SRui Miguel Silva goto pm_disable;
999a0701b62SRui Miguel Silva
1000a0701b62SRui Miguel Silva return 0;
1001a0701b62SRui Miguel Silva
1002a0701b62SRui Miguel Silva pm_disable:
1003a0701b62SRui Miguel Silva pm_runtime_disable(dev);
1004a0701b62SRui Miguel Silva pm_runtime_set_suspended(dev);
1005a0701b62SRui Miguel Silva
1006a0701b62SRui Miguel Silva return ret;
1007a0701b62SRui Miguel Silva }
100802e082c4SJonathan Cameron EXPORT_SYMBOL_NS_GPL(fxas21002c_core_probe, IIO_FXAS21002C);
1009a0701b62SRui Miguel Silva
fxas21002c_core_remove(struct device * dev)1010a0701b62SRui Miguel Silva void fxas21002c_core_remove(struct device *dev)
1011a0701b62SRui Miguel Silva {
1012a0701b62SRui Miguel Silva struct iio_dev *indio_dev = dev_get_drvdata(dev);
1013a0701b62SRui Miguel Silva
1014a0701b62SRui Miguel Silva iio_device_unregister(indio_dev);
1015a0701b62SRui Miguel Silva
1016a0701b62SRui Miguel Silva pm_runtime_disable(dev);
1017a0701b62SRui Miguel Silva pm_runtime_set_suspended(dev);
1018a0701b62SRui Miguel Silva }
101902e082c4SJonathan Cameron EXPORT_SYMBOL_NS_GPL(fxas21002c_core_remove, IIO_FXAS21002C);
1020a0701b62SRui Miguel Silva
fxas21002c_suspend(struct device * dev)102102e082c4SJonathan Cameron static int fxas21002c_suspend(struct device *dev)
1022a0701b62SRui Miguel Silva {
1023a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
1024a0701b62SRui Miguel Silva
1025a0701b62SRui Miguel Silva fxas21002c_mode_set(data, FXAS21002C_MODE_STANDBY);
1026a0701b62SRui Miguel Silva fxas21002c_power_disable(data);
1027a0701b62SRui Miguel Silva
1028a0701b62SRui Miguel Silva return 0;
1029a0701b62SRui Miguel Silva }
1030a0701b62SRui Miguel Silva
fxas21002c_resume(struct device * dev)103102e082c4SJonathan Cameron static int fxas21002c_resume(struct device *dev)
1032a0701b62SRui Miguel Silva {
1033a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
1034a0701b62SRui Miguel Silva int ret;
1035a0701b62SRui Miguel Silva
1036a0701b62SRui Miguel Silva ret = fxas21002c_power_enable(data);
1037a0701b62SRui Miguel Silva if (ret < 0)
1038a0701b62SRui Miguel Silva return ret;
1039a0701b62SRui Miguel Silva
1040a0701b62SRui Miguel Silva return fxas21002c_mode_set(data, data->prev_mode);
1041a0701b62SRui Miguel Silva }
1042a0701b62SRui Miguel Silva
fxas21002c_runtime_suspend(struct device * dev)104302e082c4SJonathan Cameron static int fxas21002c_runtime_suspend(struct device *dev)
1044a0701b62SRui Miguel Silva {
1045a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
1046a0701b62SRui Miguel Silva
1047a0701b62SRui Miguel Silva return fxas21002c_mode_set(data, FXAS21002C_MODE_READY);
1048a0701b62SRui Miguel Silva }
1049a0701b62SRui Miguel Silva
fxas21002c_runtime_resume(struct device * dev)105002e082c4SJonathan Cameron static int fxas21002c_runtime_resume(struct device *dev)
1051a0701b62SRui Miguel Silva {
1052a0701b62SRui Miguel Silva struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
1053a0701b62SRui Miguel Silva
1054a0701b62SRui Miguel Silva return fxas21002c_mode_set(data, FXAS21002C_MODE_ACTIVE);
1055a0701b62SRui Miguel Silva }
1056a0701b62SRui Miguel Silva
105702e082c4SJonathan Cameron EXPORT_NS_GPL_DEV_PM_OPS(fxas21002c_pm_ops, IIO_FXAS21002C) = {
105802e082c4SJonathan Cameron SYSTEM_SLEEP_PM_OPS(fxas21002c_suspend, fxas21002c_resume)
105902e082c4SJonathan Cameron RUNTIME_PM_OPS(fxas21002c_runtime_suspend, fxas21002c_runtime_resume,
106002e082c4SJonathan Cameron NULL)
1061a0701b62SRui Miguel Silva };
1062a0701b62SRui Miguel Silva
1063a0701b62SRui Miguel Silva MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
1064a0701b62SRui Miguel Silva MODULE_LICENSE("GPL v2");
1065a0701b62SRui Miguel Silva MODULE_DESCRIPTION("FXAS21002C Gyro driver");
1066