1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * NXP FXLS8962AF/FXLS8964AF Accelerometer Core Driver |
4 | * |
5 | * Copyright 2021 Connected Cars A/S |
6 | * |
7 | * Datasheet: |
8 | * https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf |
9 | * https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf |
10 | * |
11 | * Errata: |
12 | * https://www.nxp.com/docs/en/errata/ES_FXLS8962AF.pdf |
13 | */ |
14 | |
15 | #include <linux/bits.h> |
16 | #include <linux/bitfield.h> |
17 | #include <linux/i2c.h> |
18 | #include <linux/module.h> |
19 | #include <linux/of_irq.h> |
20 | #include <linux/pm_runtime.h> |
21 | #include <linux/regulator/consumer.h> |
22 | #include <linux/regmap.h> |
23 | |
24 | #include <linux/iio/buffer.h> |
25 | #include <linux/iio/events.h> |
26 | #include <linux/iio/iio.h> |
27 | #include <linux/iio/kfifo_buf.h> |
28 | #include <linux/iio/sysfs.h> |
29 | |
30 | #include "fxls8962af.h" |
31 | |
32 | #define FXLS8962AF_INT_STATUS 0x00 |
33 | #define FXLS8962AF_INT_STATUS_SRC_BOOT BIT(0) |
34 | #define FXLS8962AF_INT_STATUS_SRC_SDCD_OT BIT(4) |
35 | #define FXLS8962AF_INT_STATUS_SRC_BUF BIT(5) |
36 | #define FXLS8962AF_INT_STATUS_SRC_DRDY BIT(7) |
37 | #define FXLS8962AF_TEMP_OUT 0x01 |
38 | #define FXLS8962AF_VECM_LSB 0x02 |
39 | #define FXLS8962AF_OUT_X_LSB 0x04 |
40 | #define FXLS8962AF_OUT_Y_LSB 0x06 |
41 | #define FXLS8962AF_OUT_Z_LSB 0x08 |
42 | #define FXLS8962AF_BUF_STATUS 0x0b |
43 | #define FXLS8962AF_BUF_STATUS_BUF_CNT GENMASK(5, 0) |
44 | #define FXLS8962AF_BUF_STATUS_BUF_OVF BIT(6) |
45 | #define FXLS8962AF_BUF_STATUS_BUF_WMRK BIT(7) |
46 | #define FXLS8962AF_BUF_X_LSB 0x0c |
47 | #define FXLS8962AF_BUF_Y_LSB 0x0e |
48 | #define FXLS8962AF_BUF_Z_LSB 0x10 |
49 | |
50 | #define FXLS8962AF_PROD_REV 0x12 |
51 | #define FXLS8962AF_WHO_AM_I 0x13 |
52 | |
53 | #define FXLS8962AF_SYS_MODE 0x14 |
54 | #define FXLS8962AF_SENS_CONFIG1 0x15 |
55 | #define FXLS8962AF_SENS_CONFIG1_ACTIVE BIT(0) |
56 | #define FXLS8962AF_SENS_CONFIG1_RST BIT(7) |
57 | #define FXLS8962AF_SC1_FSR_MASK GENMASK(2, 1) |
58 | #define FXLS8962AF_SC1_FSR_PREP(x) FIELD_PREP(FXLS8962AF_SC1_FSR_MASK, (x)) |
59 | #define FXLS8962AF_SC1_FSR_GET(x) FIELD_GET(FXLS8962AF_SC1_FSR_MASK, (x)) |
60 | |
61 | #define FXLS8962AF_SENS_CONFIG2 0x16 |
62 | #define FXLS8962AF_SENS_CONFIG3 0x17 |
63 | #define FXLS8962AF_SC3_WAKE_ODR_MASK GENMASK(7, 4) |
64 | #define FXLS8962AF_SC3_WAKE_ODR_PREP(x) FIELD_PREP(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) |
65 | #define FXLS8962AF_SC3_WAKE_ODR_GET(x) FIELD_GET(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) |
66 | #define FXLS8962AF_SENS_CONFIG4 0x18 |
67 | #define FXLS8962AF_SC4_INT_PP_OD_MASK BIT(1) |
68 | #define FXLS8962AF_SC4_INT_PP_OD_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_PP_OD_MASK, (x)) |
69 | #define FXLS8962AF_SC4_INT_POL_MASK BIT(0) |
70 | #define FXLS8962AF_SC4_INT_POL_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_POL_MASK, (x)) |
71 | #define FXLS8962AF_SENS_CONFIG5 0x19 |
72 | |
73 | #define FXLS8962AF_WAKE_IDLE_LSB 0x1b |
74 | #define FXLS8962AF_SLEEP_IDLE_LSB 0x1c |
75 | #define FXLS8962AF_ASLP_COUNT_LSB 0x1e |
76 | |
77 | #define FXLS8962AF_INT_EN 0x20 |
78 | #define FXLS8962AF_INT_EN_SDCD_OT_EN BIT(5) |
79 | #define FXLS8962AF_INT_EN_BUF_EN BIT(6) |
80 | #define FXLS8962AF_INT_PIN_SEL 0x21 |
81 | #define FXLS8962AF_INT_PIN_SEL_MASK GENMASK(7, 0) |
82 | #define FXLS8962AF_INT_PIN_SEL_INT1 0x00 |
83 | #define FXLS8962AF_INT_PIN_SEL_INT2 GENMASK(7, 0) |
84 | |
85 | #define FXLS8962AF_OFF_X 0x22 |
86 | #define FXLS8962AF_OFF_Y 0x23 |
87 | #define FXLS8962AF_OFF_Z 0x24 |
88 | |
89 | #define FXLS8962AF_BUF_CONFIG1 0x26 |
90 | #define FXLS8962AF_BC1_BUF_MODE_MASK GENMASK(6, 5) |
91 | #define FXLS8962AF_BC1_BUF_MODE_PREP(x) FIELD_PREP(FXLS8962AF_BC1_BUF_MODE_MASK, (x)) |
92 | #define FXLS8962AF_BUF_CONFIG2 0x27 |
93 | #define FXLS8962AF_BUF_CONFIG2_BUF_WMRK GENMASK(5, 0) |
94 | |
95 | #define FXLS8962AF_ORIENT_STATUS 0x28 |
96 | #define FXLS8962AF_ORIENT_CONFIG 0x29 |
97 | #define FXLS8962AF_ORIENT_DBCOUNT 0x2a |
98 | #define FXLS8962AF_ORIENT_BF_ZCOMP 0x2b |
99 | #define FXLS8962AF_ORIENT_THS_REG 0x2c |
100 | |
101 | #define FXLS8962AF_SDCD_INT_SRC1 0x2d |
102 | #define FXLS8962AF_SDCD_INT_SRC1_X_OT BIT(5) |
103 | #define FXLS8962AF_SDCD_INT_SRC1_X_POL BIT(4) |
104 | #define FXLS8962AF_SDCD_INT_SRC1_Y_OT BIT(3) |
105 | #define FXLS8962AF_SDCD_INT_SRC1_Y_POL BIT(2) |
106 | #define FXLS8962AF_SDCD_INT_SRC1_Z_OT BIT(1) |
107 | #define FXLS8962AF_SDCD_INT_SRC1_Z_POL BIT(0) |
108 | #define FXLS8962AF_SDCD_INT_SRC2 0x2e |
109 | #define FXLS8962AF_SDCD_CONFIG1 0x2f |
110 | #define FXLS8962AF_SDCD_CONFIG1_Z_OT_EN BIT(3) |
111 | #define FXLS8962AF_SDCD_CONFIG1_Y_OT_EN BIT(4) |
112 | #define FXLS8962AF_SDCD_CONFIG1_X_OT_EN BIT(5) |
113 | #define FXLS8962AF_SDCD_CONFIG1_OT_ELE BIT(7) |
114 | #define FXLS8962AF_SDCD_CONFIG2 0x30 |
115 | #define FXLS8962AF_SDCD_CONFIG2_SDCD_EN BIT(7) |
116 | #define FXLS8962AF_SC2_REF_UPDM_AC GENMASK(6, 5) |
117 | #define FXLS8962AF_SDCD_OT_DBCNT 0x31 |
118 | #define FXLS8962AF_SDCD_WT_DBCNT 0x32 |
119 | #define FXLS8962AF_SDCD_LTHS_LSB 0x33 |
120 | #define FXLS8962AF_SDCD_UTHS_LSB 0x35 |
121 | |
122 | #define FXLS8962AF_SELF_TEST_CONFIG1 0x37 |
123 | #define FXLS8962AF_SELF_TEST_CONFIG2 0x38 |
124 | |
125 | #define FXLS8962AF_MAX_REG 0x38 |
126 | |
127 | #define FXLS8962AF_DEVICE_ID 0x62 |
128 | #define FXLS8964AF_DEVICE_ID 0x84 |
129 | |
130 | /* Raw temp channel offset */ |
131 | #define FXLS8962AF_TEMP_CENTER_VAL 25 |
132 | |
133 | #define FXLS8962AF_AUTO_SUSPEND_DELAY_MS 2000 |
134 | |
135 | #define FXLS8962AF_FIFO_LENGTH 32 |
136 | #define FXLS8962AF_SCALE_TABLE_LEN 4 |
137 | #define FXLS8962AF_SAMP_FREQ_TABLE_LEN 13 |
138 | |
139 | static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = { |
140 | {0, IIO_G_TO_M_S_2(980000)}, |
141 | {0, IIO_G_TO_M_S_2(1950000)}, |
142 | {0, IIO_G_TO_M_S_2(3910000)}, |
143 | {0, IIO_G_TO_M_S_2(7810000)}, |
144 | }; |
145 | |
146 | static const int fxls8962af_samp_freq_table[FXLS8962AF_SAMP_FREQ_TABLE_LEN][2] = { |
147 | {3200, 0}, {1600, 0}, {800, 0}, {400, 0}, {200, 0}, {100, 0}, |
148 | {50, 0}, {25, 0}, {12, 500000}, {6, 250000}, {3, 125000}, |
149 | {1, 563000}, {0, 781000}, |
150 | }; |
151 | |
152 | struct fxls8962af_chip_info { |
153 | const char *name; |
154 | const struct iio_chan_spec *channels; |
155 | int num_channels; |
156 | u8 chip_id; |
157 | }; |
158 | |
159 | struct fxls8962af_data { |
160 | struct regmap *regmap; |
161 | const struct fxls8962af_chip_info *chip_info; |
162 | struct { |
163 | __le16 channels[3]; |
164 | s64 ts __aligned(8); |
165 | } scan; |
166 | int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ |
167 | struct iio_mount_matrix orientation; |
168 | int irq; |
169 | u8 watermark; |
170 | u8 enable_event; |
171 | u16 lower_thres; |
172 | u16 upper_thres; |
173 | }; |
174 | |
175 | const struct regmap_config fxls8962af_i2c_regmap_conf = { |
176 | .reg_bits = 8, |
177 | .val_bits = 8, |
178 | .max_register = FXLS8962AF_MAX_REG, |
179 | }; |
180 | EXPORT_SYMBOL_NS_GPL(fxls8962af_i2c_regmap_conf, IIO_FXLS8962AF); |
181 | |
182 | const struct regmap_config fxls8962af_spi_regmap_conf = { |
183 | .reg_bits = 8, |
184 | .pad_bits = 8, |
185 | .val_bits = 8, |
186 | .max_register = FXLS8962AF_MAX_REG, |
187 | }; |
188 | EXPORT_SYMBOL_NS_GPL(fxls8962af_spi_regmap_conf, IIO_FXLS8962AF); |
189 | |
190 | enum { |
191 | fxls8962af_idx_x, |
192 | fxls8962af_idx_y, |
193 | fxls8962af_idx_z, |
194 | fxls8962af_idx_ts, |
195 | }; |
196 | |
197 | enum fxls8962af_int_pin { |
198 | FXLS8962AF_PIN_INT1, |
199 | FXLS8962AF_PIN_INT2, |
200 | }; |
201 | |
202 | static int fxls8962af_power_on(struct fxls8962af_data *data) |
203 | { |
204 | struct device *dev = regmap_get_device(map: data->regmap); |
205 | int ret; |
206 | |
207 | ret = pm_runtime_resume_and_get(dev); |
208 | if (ret) |
209 | dev_err(dev, "failed to power on\n" ); |
210 | |
211 | return ret; |
212 | } |
213 | |
214 | static int fxls8962af_power_off(struct fxls8962af_data *data) |
215 | { |
216 | struct device *dev = regmap_get_device(map: data->regmap); |
217 | int ret; |
218 | |
219 | pm_runtime_mark_last_busy(dev); |
220 | ret = pm_runtime_put_autosuspend(dev); |
221 | if (ret) |
222 | dev_err(dev, "failed to power off\n" ); |
223 | |
224 | return ret; |
225 | } |
226 | |
227 | static int fxls8962af_standby(struct fxls8962af_data *data) |
228 | { |
229 | return regmap_update_bits(map: data->regmap, FXLS8962AF_SENS_CONFIG1, |
230 | FXLS8962AF_SENS_CONFIG1_ACTIVE, val: 0); |
231 | } |
232 | |
233 | static int fxls8962af_active(struct fxls8962af_data *data) |
234 | { |
235 | return regmap_update_bits(map: data->regmap, FXLS8962AF_SENS_CONFIG1, |
236 | FXLS8962AF_SENS_CONFIG1_ACTIVE, val: 1); |
237 | } |
238 | |
239 | static int fxls8962af_is_active(struct fxls8962af_data *data) |
240 | { |
241 | unsigned int reg; |
242 | int ret; |
243 | |
244 | ret = regmap_read(map: data->regmap, FXLS8962AF_SENS_CONFIG1, val: ®); |
245 | if (ret) |
246 | return ret; |
247 | |
248 | return reg & FXLS8962AF_SENS_CONFIG1_ACTIVE; |
249 | } |
250 | |
251 | static int fxls8962af_get_out(struct fxls8962af_data *data, |
252 | struct iio_chan_spec const *chan, int *val) |
253 | { |
254 | struct device *dev = regmap_get_device(map: data->regmap); |
255 | __le16 raw_val; |
256 | int is_active; |
257 | int ret; |
258 | |
259 | is_active = fxls8962af_is_active(data); |
260 | if (!is_active) { |
261 | ret = fxls8962af_power_on(data); |
262 | if (ret) |
263 | return ret; |
264 | } |
265 | |
266 | ret = regmap_bulk_read(map: data->regmap, reg: chan->address, |
267 | val: &raw_val, val_count: sizeof(data->lower_thres)); |
268 | |
269 | if (!is_active) |
270 | fxls8962af_power_off(data); |
271 | |
272 | if (ret) { |
273 | dev_err(dev, "failed to get out reg 0x%lx\n" , chan->address); |
274 | return ret; |
275 | } |
276 | |
277 | *val = sign_extend32(le16_to_cpu(raw_val), |
278 | index: chan->scan_type.realbits - 1); |
279 | |
280 | return IIO_VAL_INT; |
281 | } |
282 | |
283 | static int fxls8962af_read_avail(struct iio_dev *indio_dev, |
284 | struct iio_chan_spec const *chan, |
285 | const int **vals, int *type, int *length, |
286 | long mask) |
287 | { |
288 | switch (mask) { |
289 | case IIO_CHAN_INFO_SCALE: |
290 | *type = IIO_VAL_INT_PLUS_NANO; |
291 | *vals = (int *)fxls8962af_scale_table; |
292 | *length = ARRAY_SIZE(fxls8962af_scale_table) * 2; |
293 | return IIO_AVAIL_LIST; |
294 | case IIO_CHAN_INFO_SAMP_FREQ: |
295 | *type = IIO_VAL_INT_PLUS_MICRO; |
296 | *vals = (int *)fxls8962af_samp_freq_table; |
297 | *length = ARRAY_SIZE(fxls8962af_samp_freq_table) * 2; |
298 | return IIO_AVAIL_LIST; |
299 | default: |
300 | return -EINVAL; |
301 | } |
302 | } |
303 | |
304 | static int fxls8962af_write_raw_get_fmt(struct iio_dev *indio_dev, |
305 | struct iio_chan_spec const *chan, |
306 | long mask) |
307 | { |
308 | switch (mask) { |
309 | case IIO_CHAN_INFO_SCALE: |
310 | return IIO_VAL_INT_PLUS_NANO; |
311 | case IIO_CHAN_INFO_SAMP_FREQ: |
312 | return IIO_VAL_INT_PLUS_MICRO; |
313 | default: |
314 | return IIO_VAL_INT_PLUS_NANO; |
315 | } |
316 | } |
317 | |
318 | static int fxls8962af_update_config(struct fxls8962af_data *data, u8 reg, |
319 | u8 mask, u8 val) |
320 | { |
321 | int ret; |
322 | int is_active; |
323 | |
324 | is_active = fxls8962af_is_active(data); |
325 | if (is_active) { |
326 | ret = fxls8962af_standby(data); |
327 | if (ret) |
328 | return ret; |
329 | } |
330 | |
331 | ret = regmap_update_bits(map: data->regmap, reg, mask, val); |
332 | if (ret) |
333 | return ret; |
334 | |
335 | if (is_active) { |
336 | ret = fxls8962af_active(data); |
337 | if (ret) |
338 | return ret; |
339 | } |
340 | |
341 | return 0; |
342 | } |
343 | |
344 | static int fxls8962af_set_full_scale(struct fxls8962af_data *data, u32 scale) |
345 | { |
346 | int i; |
347 | |
348 | for (i = 0; i < ARRAY_SIZE(fxls8962af_scale_table); i++) |
349 | if (scale == fxls8962af_scale_table[i][1]) |
350 | break; |
351 | |
352 | if (i == ARRAY_SIZE(fxls8962af_scale_table)) |
353 | return -EINVAL; |
354 | |
355 | return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG1, |
356 | FXLS8962AF_SC1_FSR_MASK, |
357 | FXLS8962AF_SC1_FSR_PREP(i)); |
358 | } |
359 | |
360 | static unsigned int fxls8962af_read_full_scale(struct fxls8962af_data *data, |
361 | int *val) |
362 | { |
363 | int ret; |
364 | unsigned int reg; |
365 | u8 range_idx; |
366 | |
367 | ret = regmap_read(map: data->regmap, FXLS8962AF_SENS_CONFIG1, val: ®); |
368 | if (ret) |
369 | return ret; |
370 | |
371 | range_idx = FXLS8962AF_SC1_FSR_GET(reg); |
372 | |
373 | *val = fxls8962af_scale_table[range_idx][1]; |
374 | |
375 | return IIO_VAL_INT_PLUS_NANO; |
376 | } |
377 | |
378 | static int fxls8962af_set_samp_freq(struct fxls8962af_data *data, u32 val, |
379 | u32 val2) |
380 | { |
381 | int i; |
382 | |
383 | for (i = 0; i < ARRAY_SIZE(fxls8962af_samp_freq_table); i++) |
384 | if (val == fxls8962af_samp_freq_table[i][0] && |
385 | val2 == fxls8962af_samp_freq_table[i][1]) |
386 | break; |
387 | |
388 | if (i == ARRAY_SIZE(fxls8962af_samp_freq_table)) |
389 | return -EINVAL; |
390 | |
391 | return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG3, |
392 | FXLS8962AF_SC3_WAKE_ODR_MASK, |
393 | FXLS8962AF_SC3_WAKE_ODR_PREP(i)); |
394 | } |
395 | |
396 | static unsigned int fxls8962af_read_samp_freq(struct fxls8962af_data *data, |
397 | int *val, int *val2) |
398 | { |
399 | int ret; |
400 | unsigned int reg; |
401 | u8 range_idx; |
402 | |
403 | ret = regmap_read(map: data->regmap, FXLS8962AF_SENS_CONFIG3, val: ®); |
404 | if (ret) |
405 | return ret; |
406 | |
407 | range_idx = FXLS8962AF_SC3_WAKE_ODR_GET(reg); |
408 | |
409 | *val = fxls8962af_samp_freq_table[range_idx][0]; |
410 | *val2 = fxls8962af_samp_freq_table[range_idx][1]; |
411 | |
412 | return IIO_VAL_INT_PLUS_MICRO; |
413 | } |
414 | |
415 | static int fxls8962af_read_raw(struct iio_dev *indio_dev, |
416 | struct iio_chan_spec const *chan, |
417 | int *val, int *val2, long mask) |
418 | { |
419 | struct fxls8962af_data *data = iio_priv(indio_dev); |
420 | |
421 | switch (mask) { |
422 | case IIO_CHAN_INFO_RAW: |
423 | switch (chan->type) { |
424 | case IIO_TEMP: |
425 | case IIO_ACCEL: |
426 | return fxls8962af_get_out(data, chan, val); |
427 | default: |
428 | return -EINVAL; |
429 | } |
430 | case IIO_CHAN_INFO_OFFSET: |
431 | if (chan->type != IIO_TEMP) |
432 | return -EINVAL; |
433 | |
434 | *val = FXLS8962AF_TEMP_CENTER_VAL; |
435 | return IIO_VAL_INT; |
436 | case IIO_CHAN_INFO_SCALE: |
437 | *val = 0; |
438 | return fxls8962af_read_full_scale(data, val: val2); |
439 | case IIO_CHAN_INFO_SAMP_FREQ: |
440 | return fxls8962af_read_samp_freq(data, val, val2); |
441 | default: |
442 | return -EINVAL; |
443 | } |
444 | } |
445 | |
446 | static int fxls8962af_write_raw(struct iio_dev *indio_dev, |
447 | struct iio_chan_spec const *chan, |
448 | int val, int val2, long mask) |
449 | { |
450 | struct fxls8962af_data *data = iio_priv(indio_dev); |
451 | int ret; |
452 | |
453 | switch (mask) { |
454 | case IIO_CHAN_INFO_SCALE: |
455 | if (val != 0) |
456 | return -EINVAL; |
457 | |
458 | ret = iio_device_claim_direct_mode(indio_dev); |
459 | if (ret) |
460 | return ret; |
461 | |
462 | ret = fxls8962af_set_full_scale(data, scale: val2); |
463 | |
464 | iio_device_release_direct_mode(indio_dev); |
465 | return ret; |
466 | case IIO_CHAN_INFO_SAMP_FREQ: |
467 | ret = iio_device_claim_direct_mode(indio_dev); |
468 | if (ret) |
469 | return ret; |
470 | |
471 | ret = fxls8962af_set_samp_freq(data, val, val2); |
472 | |
473 | iio_device_release_direct_mode(indio_dev); |
474 | return ret; |
475 | default: |
476 | return -EINVAL; |
477 | } |
478 | } |
479 | |
480 | static int fxls8962af_event_setup(struct fxls8962af_data *data, int state) |
481 | { |
482 | /* Enable wakeup interrupt */ |
483 | int mask = FXLS8962AF_INT_EN_SDCD_OT_EN; |
484 | int value = state ? mask : 0; |
485 | |
486 | return regmap_update_bits(map: data->regmap, FXLS8962AF_INT_EN, mask, val: value); |
487 | } |
488 | |
489 | static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val) |
490 | { |
491 | struct fxls8962af_data *data = iio_priv(indio_dev); |
492 | |
493 | if (val > FXLS8962AF_FIFO_LENGTH) |
494 | val = FXLS8962AF_FIFO_LENGTH; |
495 | |
496 | data->watermark = val; |
497 | |
498 | return 0; |
499 | } |
500 | |
501 | static int __fxls8962af_set_thresholds(struct fxls8962af_data *data, |
502 | const struct iio_chan_spec *chan, |
503 | enum iio_event_direction dir, |
504 | int val) |
505 | { |
506 | switch (dir) { |
507 | case IIO_EV_DIR_FALLING: |
508 | data->lower_thres = val; |
509 | return regmap_bulk_write(map: data->regmap, FXLS8962AF_SDCD_LTHS_LSB, |
510 | val: &data->lower_thres, val_count: sizeof(data->lower_thres)); |
511 | case IIO_EV_DIR_RISING: |
512 | data->upper_thres = val; |
513 | return regmap_bulk_write(map: data->regmap, FXLS8962AF_SDCD_UTHS_LSB, |
514 | val: &data->upper_thres, val_count: sizeof(data->upper_thres)); |
515 | default: |
516 | return -EINVAL; |
517 | } |
518 | } |
519 | |
520 | static int fxls8962af_read_event(struct iio_dev *indio_dev, |
521 | const struct iio_chan_spec *chan, |
522 | enum iio_event_type type, |
523 | enum iio_event_direction dir, |
524 | enum iio_event_info info, |
525 | int *val, int *val2) |
526 | { |
527 | struct fxls8962af_data *data = iio_priv(indio_dev); |
528 | int ret; |
529 | |
530 | if (type != IIO_EV_TYPE_THRESH) |
531 | return -EINVAL; |
532 | |
533 | switch (dir) { |
534 | case IIO_EV_DIR_FALLING: |
535 | ret = regmap_bulk_read(map: data->regmap, FXLS8962AF_SDCD_LTHS_LSB, |
536 | val: &data->lower_thres, val_count: sizeof(data->lower_thres)); |
537 | if (ret) |
538 | return ret; |
539 | |
540 | *val = sign_extend32(value: data->lower_thres, index: chan->scan_type.realbits - 1); |
541 | return IIO_VAL_INT; |
542 | case IIO_EV_DIR_RISING: |
543 | ret = regmap_bulk_read(map: data->regmap, FXLS8962AF_SDCD_UTHS_LSB, |
544 | val: &data->upper_thres, val_count: sizeof(data->upper_thres)); |
545 | if (ret) |
546 | return ret; |
547 | |
548 | *val = sign_extend32(value: data->upper_thres, index: chan->scan_type.realbits - 1); |
549 | return IIO_VAL_INT; |
550 | default: |
551 | return -EINVAL; |
552 | } |
553 | } |
554 | |
555 | static int fxls8962af_write_event(struct iio_dev *indio_dev, |
556 | const struct iio_chan_spec *chan, |
557 | enum iio_event_type type, |
558 | enum iio_event_direction dir, |
559 | enum iio_event_info info, |
560 | int val, int val2) |
561 | { |
562 | struct fxls8962af_data *data = iio_priv(indio_dev); |
563 | int ret, val_masked; |
564 | |
565 | if (type != IIO_EV_TYPE_THRESH) |
566 | return -EINVAL; |
567 | |
568 | if (val < -2048 || val > 2047) |
569 | return -EINVAL; |
570 | |
571 | if (data->enable_event) |
572 | return -EBUSY; |
573 | |
574 | val_masked = val & GENMASK(11, 0); |
575 | if (fxls8962af_is_active(data)) { |
576 | ret = fxls8962af_standby(data); |
577 | if (ret) |
578 | return ret; |
579 | |
580 | ret = __fxls8962af_set_thresholds(data, chan, dir, val: val_masked); |
581 | if (ret) |
582 | return ret; |
583 | |
584 | return fxls8962af_active(data); |
585 | } else { |
586 | return __fxls8962af_set_thresholds(data, chan, dir, val: val_masked); |
587 | } |
588 | } |
589 | |
590 | static int |
591 | fxls8962af_read_event_config(struct iio_dev *indio_dev, |
592 | const struct iio_chan_spec *chan, |
593 | enum iio_event_type type, |
594 | enum iio_event_direction dir) |
595 | { |
596 | struct fxls8962af_data *data = iio_priv(indio_dev); |
597 | |
598 | if (type != IIO_EV_TYPE_THRESH) |
599 | return -EINVAL; |
600 | |
601 | switch (chan->channel2) { |
602 | case IIO_MOD_X: |
603 | return !!(FXLS8962AF_SDCD_CONFIG1_X_OT_EN & data->enable_event); |
604 | case IIO_MOD_Y: |
605 | return !!(FXLS8962AF_SDCD_CONFIG1_Y_OT_EN & data->enable_event); |
606 | case IIO_MOD_Z: |
607 | return !!(FXLS8962AF_SDCD_CONFIG1_Z_OT_EN & data->enable_event); |
608 | default: |
609 | return -EINVAL; |
610 | } |
611 | } |
612 | |
613 | static int |
614 | fxls8962af_write_event_config(struct iio_dev *indio_dev, |
615 | const struct iio_chan_spec *chan, |
616 | enum iio_event_type type, |
617 | enum iio_event_direction dir, int state) |
618 | { |
619 | struct fxls8962af_data *data = iio_priv(indio_dev); |
620 | u8 enable_event, enable_bits; |
621 | int ret, value; |
622 | |
623 | if (type != IIO_EV_TYPE_THRESH) |
624 | return -EINVAL; |
625 | |
626 | switch (chan->channel2) { |
627 | case IIO_MOD_X: |
628 | enable_bits = FXLS8962AF_SDCD_CONFIG1_X_OT_EN; |
629 | break; |
630 | case IIO_MOD_Y: |
631 | enable_bits = FXLS8962AF_SDCD_CONFIG1_Y_OT_EN; |
632 | break; |
633 | case IIO_MOD_Z: |
634 | enable_bits = FXLS8962AF_SDCD_CONFIG1_Z_OT_EN; |
635 | break; |
636 | default: |
637 | return -EINVAL; |
638 | } |
639 | |
640 | if (state) |
641 | enable_event = data->enable_event | enable_bits; |
642 | else |
643 | enable_event = data->enable_event & ~enable_bits; |
644 | |
645 | if (data->enable_event == enable_event) |
646 | return 0; |
647 | |
648 | ret = fxls8962af_standby(data); |
649 | if (ret) |
650 | return ret; |
651 | |
652 | /* Enable events */ |
653 | value = enable_event | FXLS8962AF_SDCD_CONFIG1_OT_ELE; |
654 | ret = regmap_write(map: data->regmap, FXLS8962AF_SDCD_CONFIG1, val: value); |
655 | if (ret) |
656 | return ret; |
657 | |
658 | /* |
659 | * Enable update of SDCD_REF_X/Y/Z values with the current decimated and |
660 | * trimmed X/Y/Z acceleration input data. This allows for acceleration |
661 | * slope detection with Data(n) to Data(n–1) always used as the input |
662 | * to the window comparator. |
663 | */ |
664 | value = enable_event ? |
665 | FXLS8962AF_SDCD_CONFIG2_SDCD_EN | FXLS8962AF_SC2_REF_UPDM_AC : |
666 | 0x00; |
667 | ret = regmap_write(map: data->regmap, FXLS8962AF_SDCD_CONFIG2, val: value); |
668 | if (ret) |
669 | return ret; |
670 | |
671 | ret = fxls8962af_event_setup(data, state); |
672 | if (ret) |
673 | return ret; |
674 | |
675 | data->enable_event = enable_event; |
676 | |
677 | if (data->enable_event) { |
678 | fxls8962af_active(data); |
679 | ret = fxls8962af_power_on(data); |
680 | } else { |
681 | ret = iio_device_claim_direct_mode(indio_dev); |
682 | if (ret) |
683 | return ret; |
684 | |
685 | /* Not in buffered mode so disable power */ |
686 | ret = fxls8962af_power_off(data); |
687 | |
688 | iio_device_release_direct_mode(indio_dev); |
689 | } |
690 | |
691 | return ret; |
692 | } |
693 | |
694 | static const struct iio_event_spec fxls8962af_event[] = { |
695 | { |
696 | .type = IIO_EV_TYPE_THRESH, |
697 | .dir = IIO_EV_DIR_EITHER, |
698 | .mask_separate = BIT(IIO_EV_INFO_ENABLE), |
699 | }, |
700 | { |
701 | .type = IIO_EV_TYPE_THRESH, |
702 | .dir = IIO_EV_DIR_FALLING, |
703 | .mask_separate = BIT(IIO_EV_INFO_VALUE), |
704 | }, |
705 | { |
706 | .type = IIO_EV_TYPE_THRESH, |
707 | .dir = IIO_EV_DIR_RISING, |
708 | .mask_separate = BIT(IIO_EV_INFO_VALUE), |
709 | }, |
710 | }; |
711 | |
712 | #define FXLS8962AF_CHANNEL(axis, reg, idx) { \ |
713 | .type = IIO_ACCEL, \ |
714 | .address = reg, \ |
715 | .modified = 1, \ |
716 | .channel2 = IIO_MOD_##axis, \ |
717 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
718 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ |
719 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
720 | .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) | \ |
721 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
722 | .scan_index = idx, \ |
723 | .scan_type = { \ |
724 | .sign = 's', \ |
725 | .realbits = 12, \ |
726 | .storagebits = 16, \ |
727 | .endianness = IIO_LE, \ |
728 | }, \ |
729 | .event_spec = fxls8962af_event, \ |
730 | .num_event_specs = ARRAY_SIZE(fxls8962af_event), \ |
731 | } |
732 | |
733 | #define FXLS8962AF_TEMP_CHANNEL { \ |
734 | .type = IIO_TEMP, \ |
735 | .address = FXLS8962AF_TEMP_OUT, \ |
736 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
737 | BIT(IIO_CHAN_INFO_OFFSET),\ |
738 | .scan_index = -1, \ |
739 | .scan_type = { \ |
740 | .realbits = 8, \ |
741 | .storagebits = 8, \ |
742 | }, \ |
743 | } |
744 | |
745 | static const struct iio_chan_spec fxls8962af_channels[] = { |
746 | FXLS8962AF_CHANNEL(X, FXLS8962AF_OUT_X_LSB, fxls8962af_idx_x), |
747 | FXLS8962AF_CHANNEL(Y, FXLS8962AF_OUT_Y_LSB, fxls8962af_idx_y), |
748 | FXLS8962AF_CHANNEL(Z, FXLS8962AF_OUT_Z_LSB, fxls8962af_idx_z), |
749 | IIO_CHAN_SOFT_TIMESTAMP(fxls8962af_idx_ts), |
750 | FXLS8962AF_TEMP_CHANNEL, |
751 | }; |
752 | |
753 | static const struct fxls8962af_chip_info fxls_chip_info_table[] = { |
754 | [fxls8962af] = { |
755 | .chip_id = FXLS8962AF_DEVICE_ID, |
756 | .name = "fxls8962af" , |
757 | .channels = fxls8962af_channels, |
758 | .num_channels = ARRAY_SIZE(fxls8962af_channels), |
759 | }, |
760 | [fxls8964af] = { |
761 | .chip_id = FXLS8964AF_DEVICE_ID, |
762 | .name = "fxls8964af" , |
763 | .channels = fxls8962af_channels, |
764 | .num_channels = ARRAY_SIZE(fxls8962af_channels), |
765 | }, |
766 | }; |
767 | |
768 | static const struct iio_info fxls8962af_info = { |
769 | .read_raw = &fxls8962af_read_raw, |
770 | .write_raw = &fxls8962af_write_raw, |
771 | .write_raw_get_fmt = fxls8962af_write_raw_get_fmt, |
772 | .read_event_value = fxls8962af_read_event, |
773 | .write_event_value = fxls8962af_write_event, |
774 | .read_event_config = fxls8962af_read_event_config, |
775 | .write_event_config = fxls8962af_write_event_config, |
776 | .read_avail = fxls8962af_read_avail, |
777 | .hwfifo_set_watermark = fxls8962af_set_watermark, |
778 | }; |
779 | |
780 | static int fxls8962af_reset(struct fxls8962af_data *data) |
781 | { |
782 | struct device *dev = regmap_get_device(map: data->regmap); |
783 | unsigned int reg; |
784 | int ret; |
785 | |
786 | ret = regmap_update_bits(map: data->regmap, FXLS8962AF_SENS_CONFIG1, |
787 | FXLS8962AF_SENS_CONFIG1_RST, |
788 | FXLS8962AF_SENS_CONFIG1_RST); |
789 | if (ret) |
790 | return ret; |
791 | |
792 | /* TBOOT1, TBOOT2, specifies we have to wait between 1 - 17.7ms */ |
793 | ret = regmap_read_poll_timeout(data->regmap, FXLS8962AF_INT_STATUS, reg, |
794 | (reg & FXLS8962AF_INT_STATUS_SRC_BOOT), |
795 | 1000, 18000); |
796 | if (ret == -ETIMEDOUT) |
797 | dev_err(dev, "reset timeout, int_status = 0x%x\n" , reg); |
798 | |
799 | return ret; |
800 | } |
801 | |
802 | static int __fxls8962af_fifo_set_mode(struct fxls8962af_data *data, bool onoff) |
803 | { |
804 | int ret; |
805 | |
806 | /* Enable watermark at max fifo size */ |
807 | ret = regmap_update_bits(map: data->regmap, FXLS8962AF_BUF_CONFIG2, |
808 | FXLS8962AF_BUF_CONFIG2_BUF_WMRK, |
809 | val: data->watermark); |
810 | if (ret) |
811 | return ret; |
812 | |
813 | return regmap_update_bits(map: data->regmap, FXLS8962AF_BUF_CONFIG1, |
814 | FXLS8962AF_BC1_BUF_MODE_MASK, |
815 | FXLS8962AF_BC1_BUF_MODE_PREP(onoff)); |
816 | } |
817 | |
818 | static int fxls8962af_buffer_preenable(struct iio_dev *indio_dev) |
819 | { |
820 | return fxls8962af_power_on(data: iio_priv(indio_dev)); |
821 | } |
822 | |
823 | static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev) |
824 | { |
825 | struct fxls8962af_data *data = iio_priv(indio_dev); |
826 | int ret; |
827 | |
828 | fxls8962af_standby(data); |
829 | |
830 | /* Enable buffer interrupt */ |
831 | ret = regmap_update_bits(map: data->regmap, FXLS8962AF_INT_EN, |
832 | FXLS8962AF_INT_EN_BUF_EN, |
833 | FXLS8962AF_INT_EN_BUF_EN); |
834 | if (ret) |
835 | return ret; |
836 | |
837 | ret = __fxls8962af_fifo_set_mode(data, onoff: true); |
838 | |
839 | fxls8962af_active(data); |
840 | |
841 | return ret; |
842 | } |
843 | |
844 | static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev) |
845 | { |
846 | struct fxls8962af_data *data = iio_priv(indio_dev); |
847 | int ret; |
848 | |
849 | fxls8962af_standby(data); |
850 | |
851 | /* Disable buffer interrupt */ |
852 | ret = regmap_update_bits(map: data->regmap, FXLS8962AF_INT_EN, |
853 | FXLS8962AF_INT_EN_BUF_EN, val: 0); |
854 | if (ret) |
855 | return ret; |
856 | |
857 | ret = __fxls8962af_fifo_set_mode(data, onoff: false); |
858 | |
859 | if (data->enable_event) |
860 | fxls8962af_active(data); |
861 | |
862 | return ret; |
863 | } |
864 | |
865 | static int fxls8962af_buffer_postdisable(struct iio_dev *indio_dev) |
866 | { |
867 | struct fxls8962af_data *data = iio_priv(indio_dev); |
868 | |
869 | if (!data->enable_event) |
870 | fxls8962af_power_off(data); |
871 | |
872 | return 0; |
873 | } |
874 | |
875 | static const struct iio_buffer_setup_ops fxls8962af_buffer_ops = { |
876 | .preenable = fxls8962af_buffer_preenable, |
877 | .postenable = fxls8962af_buffer_postenable, |
878 | .predisable = fxls8962af_buffer_predisable, |
879 | .postdisable = fxls8962af_buffer_postdisable, |
880 | }; |
881 | |
882 | static int fxls8962af_i2c_raw_read_errata3(struct fxls8962af_data *data, |
883 | u16 *buffer, int samples, |
884 | int sample_length) |
885 | { |
886 | int i, ret; |
887 | |
888 | for (i = 0; i < samples; i++) { |
889 | ret = regmap_raw_read(map: data->regmap, FXLS8962AF_BUF_X_LSB, |
890 | val: &buffer[i * 3], val_len: sample_length); |
891 | if (ret) |
892 | return ret; |
893 | } |
894 | |
895 | return 0; |
896 | } |
897 | |
898 | static int fxls8962af_fifo_transfer(struct fxls8962af_data *data, |
899 | u16 *buffer, int samples) |
900 | { |
901 | struct device *dev = regmap_get_device(map: data->regmap); |
902 | int sample_length = 3 * sizeof(*buffer); |
903 | int total_length = samples * sample_length; |
904 | int ret; |
905 | |
906 | if (i2c_verify_client(dev) && |
907 | data->chip_info->chip_id == FXLS8962AF_DEVICE_ID) |
908 | /* |
909 | * Due to errata bug (only applicable on fxls8962af): |
910 | * E3: FIFO burst read operation error using I2C interface |
911 | * We have to avoid burst reads on I2C.. |
912 | */ |
913 | ret = fxls8962af_i2c_raw_read_errata3(data, buffer, samples, |
914 | sample_length); |
915 | else |
916 | ret = regmap_raw_read(map: data->regmap, FXLS8962AF_BUF_X_LSB, val: buffer, |
917 | val_len: total_length); |
918 | |
919 | if (ret) |
920 | dev_err(dev, "Error transferring data from fifo: %d\n" , ret); |
921 | |
922 | return ret; |
923 | } |
924 | |
925 | static int fxls8962af_fifo_flush(struct iio_dev *indio_dev) |
926 | { |
927 | struct fxls8962af_data *data = iio_priv(indio_dev); |
928 | struct device *dev = regmap_get_device(map: data->regmap); |
929 | u16 buffer[FXLS8962AF_FIFO_LENGTH * 3]; |
930 | uint64_t sample_period; |
931 | unsigned int reg; |
932 | int64_t tstamp; |
933 | int ret, i; |
934 | u8 count; |
935 | |
936 | ret = regmap_read(map: data->regmap, FXLS8962AF_BUF_STATUS, val: ®); |
937 | if (ret) |
938 | return ret; |
939 | |
940 | if (reg & FXLS8962AF_BUF_STATUS_BUF_OVF) { |
941 | dev_err(dev, "Buffer overflow" ); |
942 | return -EOVERFLOW; |
943 | } |
944 | |
945 | count = reg & FXLS8962AF_BUF_STATUS_BUF_CNT; |
946 | if (!count) |
947 | return 0; |
948 | |
949 | data->old_timestamp = data->timestamp; |
950 | data->timestamp = iio_get_time_ns(indio_dev); |
951 | |
952 | /* |
953 | * Approximate timestamps for each of the sample based on the sampling, |
954 | * frequency, timestamp for last sample and number of samples. |
955 | */ |
956 | sample_period = (data->timestamp - data->old_timestamp); |
957 | do_div(sample_period, count); |
958 | tstamp = data->timestamp - (count - 1) * sample_period; |
959 | |
960 | ret = fxls8962af_fifo_transfer(data, buffer, samples: count); |
961 | if (ret) |
962 | return ret; |
963 | |
964 | /* Demux hw FIFO into kfifo. */ |
965 | for (i = 0; i < count; i++) { |
966 | int j, bit; |
967 | |
968 | j = 0; |
969 | for_each_set_bit(bit, indio_dev->active_scan_mask, |
970 | indio_dev->masklength) { |
971 | memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit], |
972 | sizeof(data->scan.channels[0])); |
973 | } |
974 | |
975 | iio_push_to_buffers_with_timestamp(indio_dev, data: &data->scan, |
976 | timestamp: tstamp); |
977 | |
978 | tstamp += sample_period; |
979 | } |
980 | |
981 | return count; |
982 | } |
983 | |
984 | static int fxls8962af_event_interrupt(struct iio_dev *indio_dev) |
985 | { |
986 | struct fxls8962af_data *data = iio_priv(indio_dev); |
987 | s64 ts = iio_get_time_ns(indio_dev); |
988 | unsigned int reg; |
989 | u64 ev_code; |
990 | int ret; |
991 | |
992 | ret = regmap_read(map: data->regmap, FXLS8962AF_SDCD_INT_SRC1, val: ®); |
993 | if (ret) |
994 | return ret; |
995 | |
996 | if (reg & FXLS8962AF_SDCD_INT_SRC1_X_OT) { |
997 | ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_X_POL ? |
998 | IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING; |
999 | iio_push_event(indio_dev, |
1000 | IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, |
1001 | IIO_EV_TYPE_THRESH, ev_code), timestamp: ts); |
1002 | } |
1003 | |
1004 | if (reg & FXLS8962AF_SDCD_INT_SRC1_Y_OT) { |
1005 | ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_Y_POL ? |
1006 | IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING; |
1007 | iio_push_event(indio_dev, |
1008 | IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, |
1009 | IIO_EV_TYPE_THRESH, ev_code), timestamp: ts); |
1010 | } |
1011 | |
1012 | if (reg & FXLS8962AF_SDCD_INT_SRC1_Z_OT) { |
1013 | ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_Z_POL ? |
1014 | IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING; |
1015 | iio_push_event(indio_dev, |
1016 | IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, |
1017 | IIO_EV_TYPE_THRESH, ev_code), timestamp: ts); |
1018 | } |
1019 | |
1020 | return 0; |
1021 | } |
1022 | |
1023 | static irqreturn_t fxls8962af_interrupt(int irq, void *p) |
1024 | { |
1025 | struct iio_dev *indio_dev = p; |
1026 | struct fxls8962af_data *data = iio_priv(indio_dev); |
1027 | unsigned int reg; |
1028 | int ret; |
1029 | |
1030 | ret = regmap_read(map: data->regmap, FXLS8962AF_INT_STATUS, val: ®); |
1031 | if (ret) |
1032 | return IRQ_NONE; |
1033 | |
1034 | if (reg & FXLS8962AF_INT_STATUS_SRC_BUF) { |
1035 | ret = fxls8962af_fifo_flush(indio_dev); |
1036 | if (ret < 0) |
1037 | return IRQ_NONE; |
1038 | |
1039 | return IRQ_HANDLED; |
1040 | } |
1041 | |
1042 | if (reg & FXLS8962AF_INT_STATUS_SRC_SDCD_OT) { |
1043 | ret = fxls8962af_event_interrupt(indio_dev); |
1044 | if (ret < 0) |
1045 | return IRQ_NONE; |
1046 | |
1047 | return IRQ_HANDLED; |
1048 | } |
1049 | |
1050 | return IRQ_NONE; |
1051 | } |
1052 | |
1053 | static void fxls8962af_pm_disable(void *dev_ptr) |
1054 | { |
1055 | struct device *dev = dev_ptr; |
1056 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
1057 | |
1058 | pm_runtime_disable(dev); |
1059 | pm_runtime_set_suspended(dev); |
1060 | pm_runtime_put_noidle(dev); |
1061 | |
1062 | fxls8962af_standby(data: iio_priv(indio_dev)); |
1063 | } |
1064 | |
1065 | static void fxls8962af_get_irq(struct device_node *of_node, |
1066 | enum fxls8962af_int_pin *pin) |
1067 | { |
1068 | int irq; |
1069 | |
1070 | irq = of_irq_get_byname(dev: of_node, name: "INT2" ); |
1071 | if (irq > 0) { |
1072 | *pin = FXLS8962AF_PIN_INT2; |
1073 | return; |
1074 | } |
1075 | |
1076 | *pin = FXLS8962AF_PIN_INT1; |
1077 | } |
1078 | |
1079 | static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq) |
1080 | { |
1081 | struct fxls8962af_data *data = iio_priv(indio_dev); |
1082 | struct device *dev = regmap_get_device(map: data->regmap); |
1083 | unsigned long irq_type; |
1084 | bool irq_active_high; |
1085 | enum fxls8962af_int_pin int_pin; |
1086 | u8 int_pin_sel; |
1087 | int ret; |
1088 | |
1089 | fxls8962af_get_irq(of_node: dev->of_node, pin: &int_pin); |
1090 | switch (int_pin) { |
1091 | case FXLS8962AF_PIN_INT1: |
1092 | int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT1; |
1093 | break; |
1094 | case FXLS8962AF_PIN_INT2: |
1095 | int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT2; |
1096 | break; |
1097 | default: |
1098 | dev_err(dev, "unsupported int pin selected\n" ); |
1099 | return -EINVAL; |
1100 | } |
1101 | |
1102 | ret = regmap_update_bits(map: data->regmap, FXLS8962AF_INT_PIN_SEL, |
1103 | FXLS8962AF_INT_PIN_SEL_MASK, val: int_pin_sel); |
1104 | if (ret) |
1105 | return ret; |
1106 | |
1107 | irq_type = irqd_get_trigger_type(d: irq_get_irq_data(irq)); |
1108 | |
1109 | switch (irq_type) { |
1110 | case IRQF_TRIGGER_HIGH: |
1111 | case IRQF_TRIGGER_RISING: |
1112 | irq_active_high = true; |
1113 | break; |
1114 | case IRQF_TRIGGER_LOW: |
1115 | case IRQF_TRIGGER_FALLING: |
1116 | irq_active_high = false; |
1117 | break; |
1118 | default: |
1119 | dev_info(dev, "mode %lx unsupported\n" , irq_type); |
1120 | return -EINVAL; |
1121 | } |
1122 | |
1123 | ret = regmap_update_bits(map: data->regmap, FXLS8962AF_SENS_CONFIG4, |
1124 | FXLS8962AF_SC4_INT_POL_MASK, |
1125 | FXLS8962AF_SC4_INT_POL_PREP(irq_active_high)); |
1126 | if (ret) |
1127 | return ret; |
1128 | |
1129 | if (device_property_read_bool(dev, propname: "drive-open-drain" )) { |
1130 | ret = regmap_update_bits(map: data->regmap, FXLS8962AF_SENS_CONFIG4, |
1131 | FXLS8962AF_SC4_INT_PP_OD_MASK, |
1132 | FXLS8962AF_SC4_INT_PP_OD_PREP(1)); |
1133 | if (ret) |
1134 | return ret; |
1135 | |
1136 | irq_type |= IRQF_SHARED; |
1137 | } |
1138 | |
1139 | return devm_request_threaded_irq(dev, |
1140 | irq, |
1141 | NULL, thread_fn: fxls8962af_interrupt, |
1142 | irqflags: irq_type | IRQF_ONESHOT, |
1143 | devname: indio_dev->name, dev_id: indio_dev); |
1144 | } |
1145 | |
1146 | int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) |
1147 | { |
1148 | struct fxls8962af_data *data; |
1149 | struct iio_dev *indio_dev; |
1150 | unsigned int reg; |
1151 | int ret, i; |
1152 | |
1153 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*data)); |
1154 | if (!indio_dev) |
1155 | return -ENOMEM; |
1156 | |
1157 | data = iio_priv(indio_dev); |
1158 | dev_set_drvdata(dev, data: indio_dev); |
1159 | data->regmap = regmap; |
1160 | data->irq = irq; |
1161 | |
1162 | ret = iio_read_mount_matrix(dev, matrix: &data->orientation); |
1163 | if (ret) |
1164 | return ret; |
1165 | |
1166 | ret = devm_regulator_get_enable(dev, id: "vdd" ); |
1167 | if (ret) |
1168 | return dev_err_probe(dev, err: ret, |
1169 | fmt: "Failed to get vdd regulator\n" ); |
1170 | |
1171 | ret = regmap_read(map: data->regmap, FXLS8962AF_WHO_AM_I, val: ®); |
1172 | if (ret) |
1173 | return ret; |
1174 | |
1175 | for (i = 0; i < ARRAY_SIZE(fxls_chip_info_table); i++) { |
1176 | if (fxls_chip_info_table[i].chip_id == reg) { |
1177 | data->chip_info = &fxls_chip_info_table[i]; |
1178 | break; |
1179 | } |
1180 | } |
1181 | if (i == ARRAY_SIZE(fxls_chip_info_table)) { |
1182 | dev_err(dev, "failed to match device in table\n" ); |
1183 | return -ENXIO; |
1184 | } |
1185 | |
1186 | indio_dev->channels = data->chip_info->channels; |
1187 | indio_dev->num_channels = data->chip_info->num_channels; |
1188 | indio_dev->name = data->chip_info->name; |
1189 | indio_dev->info = &fxls8962af_info; |
1190 | indio_dev->modes = INDIO_DIRECT_MODE; |
1191 | |
1192 | ret = fxls8962af_reset(data); |
1193 | if (ret) |
1194 | return ret; |
1195 | |
1196 | if (irq) { |
1197 | ret = fxls8962af_irq_setup(indio_dev, irq); |
1198 | if (ret) |
1199 | return ret; |
1200 | |
1201 | ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, |
1202 | &fxls8962af_buffer_ops); |
1203 | if (ret) |
1204 | return ret; |
1205 | } |
1206 | |
1207 | ret = pm_runtime_set_active(dev); |
1208 | if (ret) |
1209 | return ret; |
1210 | |
1211 | pm_runtime_enable(dev); |
1212 | pm_runtime_set_autosuspend_delay(dev, FXLS8962AF_AUTO_SUSPEND_DELAY_MS); |
1213 | pm_runtime_use_autosuspend(dev); |
1214 | |
1215 | ret = devm_add_action_or_reset(dev, fxls8962af_pm_disable, dev); |
1216 | if (ret) |
1217 | return ret; |
1218 | |
1219 | if (device_property_read_bool(dev, propname: "wakeup-source" )) |
1220 | device_init_wakeup(dev, enable: true); |
1221 | |
1222 | return devm_iio_device_register(dev, indio_dev); |
1223 | } |
1224 | EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, IIO_FXLS8962AF); |
1225 | |
1226 | static int fxls8962af_runtime_suspend(struct device *dev) |
1227 | { |
1228 | struct fxls8962af_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
1229 | int ret; |
1230 | |
1231 | ret = fxls8962af_standby(data); |
1232 | if (ret) { |
1233 | dev_err(dev, "powering off device failed\n" ); |
1234 | return ret; |
1235 | } |
1236 | |
1237 | return 0; |
1238 | } |
1239 | |
1240 | static int fxls8962af_runtime_resume(struct device *dev) |
1241 | { |
1242 | struct fxls8962af_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
1243 | |
1244 | return fxls8962af_active(data); |
1245 | } |
1246 | |
1247 | static int fxls8962af_suspend(struct device *dev) |
1248 | { |
1249 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
1250 | struct fxls8962af_data *data = iio_priv(indio_dev); |
1251 | |
1252 | if (device_may_wakeup(dev) && data->enable_event) { |
1253 | enable_irq_wake(irq: data->irq); |
1254 | |
1255 | /* |
1256 | * Disable buffer, as the buffer is so small the device will wake |
1257 | * almost immediately. |
1258 | */ |
1259 | if (iio_buffer_enabled(indio_dev)) |
1260 | fxls8962af_buffer_predisable(indio_dev); |
1261 | } else { |
1262 | fxls8962af_runtime_suspend(dev); |
1263 | } |
1264 | |
1265 | return 0; |
1266 | } |
1267 | |
1268 | static int fxls8962af_resume(struct device *dev) |
1269 | { |
1270 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
1271 | struct fxls8962af_data *data = iio_priv(indio_dev); |
1272 | |
1273 | if (device_may_wakeup(dev) && data->enable_event) { |
1274 | disable_irq_wake(irq: data->irq); |
1275 | |
1276 | if (iio_buffer_enabled(indio_dev)) |
1277 | fxls8962af_buffer_postenable(indio_dev); |
1278 | } else { |
1279 | fxls8962af_runtime_resume(dev); |
1280 | } |
1281 | |
1282 | return 0; |
1283 | } |
1284 | |
1285 | EXPORT_NS_GPL_DEV_PM_OPS(fxls8962af_pm_ops, IIO_FXLS8962AF) = { |
1286 | SYSTEM_SLEEP_PM_OPS(fxls8962af_suspend, fxls8962af_resume) |
1287 | RUNTIME_PM_OPS(fxls8962af_runtime_suspend, fxls8962af_runtime_resume, NULL) |
1288 | }; |
1289 | |
1290 | MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>" ); |
1291 | MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver" ); |
1292 | MODULE_LICENSE("GPL v2" ); |
1293 | |