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