blob: f1da1e463947c93230fa4e866a4c8a1011b09f25 [file] [log] [blame]
Mario Tesic6a86652018-04-24 11:49:14 +02001/*
2 * STMicroelectronics st_asm330lhh FIFO buffer library driver
3 *
mario tesi547c2f52020-03-18 13:36:32 +01004 * Copyright 2020 STMicroelectronics Inc.
Mario Tesic6a86652018-04-24 11:49:14 +02005 *
6 * Lorenzo Bianconi <lorenzo.bianconi@st.com>
7 *
8 * Licensed under the GPL-2.
9 */
10#include <linux/module.h>
11#include <linux/interrupt.h>
12#include <linux/irq.h>
mario tesi547c2f52020-03-18 13:36:32 +010013#include <linux/iio/iio.h>
Mario Tesic6a86652018-04-24 11:49:14 +020014#include <linux/iio/kfifo_buf.h>
15#include <linux/iio/events.h>
16#include <asm/unaligned.h>
mario tesi547c2f52020-03-18 13:36:32 +010017#include <linux/iio/buffer.h>
Mario Tesic6a86652018-04-24 11:49:14 +020018#include <linux/of.h>
19
20#include "st_asm330lhh.h"
21
22#define ST_ASM330LHH_REG_FIFO_THL_ADDR 0x07
23#define ST_ASM330LHH_REG_FIFO_LEN_MASK GENMASK(8, 0)
mario tesi547c2f52020-03-18 13:36:32 +010024#define ST_ASM330LHH_REG_FIFO_STATUS_DIFF GENMASK(9, 0)
Mario Tesic6a86652018-04-24 11:49:14 +020025#define ST_ASM330LHH_REG_FIFO_MODE_MASK GENMASK(2, 0)
26#define ST_ASM330LHH_REG_DEC_TS_MASK GENMASK(7, 6)
27#define ST_ASM330LHH_REG_HLACTIVE_ADDR 0x12
28#define ST_ASM330LHH_REG_HLACTIVE_MASK BIT(5)
29#define ST_ASM330LHH_REG_PP_OD_ADDR 0x12
30#define ST_ASM330LHH_REG_PP_OD_MASK BIT(4)
mario tesi547c2f52020-03-18 13:36:32 +010031#define ST_ASM330LHH_REG_FIFO_STATUS1_ADDR 0x3a
Mario Tesic6a86652018-04-24 11:49:14 +020032#define ST_ASM330LHH_REG_TS0_ADDR 0x40
33#define ST_ASM330LHH_REG_TS2_ADDR 0x42
34#define ST_ASM330LHH_REG_FIFO_OUT_TAG_ADDR 0x78
Mario Tesic6a86652018-04-24 11:49:14 +020035
mario tesi547c2f52020-03-18 13:36:32 +010036#define ST_ASM330LHH_SAMPLE_DISCHARD 0x7ffd
Mario Tesic6a86652018-04-24 11:49:14 +020037
mario tesi547c2f52020-03-18 13:36:32 +010038/* Timestamp convergence filter parameter */
Mario Tesic6a86652018-04-24 11:49:14 +020039#define ST_ASM330LHH_EWMA_LEVEL 120
40#define ST_ASM330LHH_EWMA_DIV 128
mario tesi547c2f52020-03-18 13:36:32 +010041
42enum {
43 ST_ASM330LHH_GYRO_TAG = 0x01,
44 ST_ASM330LHH_ACC_TAG = 0x02,
45 ST_ASM330LHH_TS_TAG = 0x04,
46};
47
Mario Tesic6a86652018-04-24 11:49:14 +020048static inline s64 st_asm330lhh_ewma(s64 old, s64 new, int weight)
49{
50 s64 diff, incr;
51
52 diff = new - old;
53 incr = div_s64((ST_ASM330LHH_EWMA_DIV - weight) * diff,
54 ST_ASM330LHH_EWMA_DIV);
55
56 return old + incr;
57}
58
59static inline int st_asm330lhh_reset_hwts(struct st_asm330lhh_hw *hw)
60{
61 u8 data = 0xaa;
62
63 hw->ts = st_asm330lhh_get_time_ns();
64 hw->ts_offset = hw->ts;
mario tesi547c2f52020-03-18 13:36:32 +010065 hw->val_ts_old = 0;
66 hw->hw_ts_high = 0;
Mario Tesic6a86652018-04-24 11:49:14 +020067 hw->tsample = 0ull;
68
Puneet Yatnalef8d7652020-03-19 09:57:34 +053069 if (hw->asm330_hrtimer)
70 st_asm330lhh_set_cpu_idle_state(true);
71
Mario Tesic6a86652018-04-24 11:49:14 +020072 return hw->tf->write(hw->dev, ST_ASM330LHH_REG_TS2_ADDR, sizeof(data),
73 &data);
74}
75
76int st_asm330lhh_set_fifo_mode(struct st_asm330lhh_hw *hw,
77 enum st_asm330lhh_fifo_mode fifo_mode)
78{
79 int err;
80
81 err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_FIFO_CTRL4_ADDR,
82 ST_ASM330LHH_REG_FIFO_MODE_MASK,
83 fifo_mode);
84 if (err < 0)
85 return err;
86
87 hw->fifo_mode = fifo_mode;
88
mario tesi547c2f52020-03-18 13:36:32 +010089 if (fifo_mode == ST_ASM330LHH_FIFO_BYPASS)
90 clear_bit(ST_ASM330LHH_HW_OPERATIONAL, &hw->state);
91 else
92 set_bit(ST_ASM330LHH_HW_OPERATIONAL, &hw->state);
93
Mario Tesic6a86652018-04-24 11:49:14 +020094 return 0;
95}
96
97static int st_asm330lhh_set_sensor_batching_odr(struct st_asm330lhh_sensor *sensor,
98 bool enable)
99{
100 struct st_asm330lhh_hw *hw = sensor->hw;
101 u8 data = 0;
102 int err;
103
104 if (enable) {
105 err = st_asm330lhh_get_odr_val(sensor->id, sensor->odr, &data);
106 if (err < 0)
107 return err;
108 }
109
110 return st_asm330lhh_write_with_mask(hw,
111 sensor->batch_addr,
112 sensor->batch_mask, data);
113}
114
Puneet yatnala80857e72018-03-07 17:30:49 +0530115int st_asm330lhh_update_watermark(struct st_asm330lhh_sensor *sensor,
Mario Tesic6a86652018-04-24 11:49:14 +0200116 u16 watermark)
117{
118 u16 fifo_watermark = ST_ASM330LHH_MAX_FIFO_DEPTH, cur_watermark = 0;
119 struct st_asm330lhh_hw *hw = sensor->hw;
120 struct st_asm330lhh_sensor *cur_sensor;
121 __le16 wdata;
122 int i, err;
123 u8 data;
124
125 for (i = 0; i < ST_ASM330LHH_ID_MAX; i++) {
mario tesi547c2f52020-03-18 13:36:32 +0100126 if (!hw->iio_devs[i])
127 continue;
128
Mario Tesic6a86652018-04-24 11:49:14 +0200129 cur_sensor = iio_priv(hw->iio_devs[i]);
130
131 if (!(hw->enable_mask & BIT(cur_sensor->id)))
132 continue;
133
134 cur_watermark = (cur_sensor == sensor) ? watermark
135 : cur_sensor->watermark;
136
137 fifo_watermark = min_t(u16, fifo_watermark, cur_watermark);
138 }
139
140 fifo_watermark = max_t(u16, fifo_watermark, 2);
mario tesi547c2f52020-03-18 13:36:32 +0100141
Mario Tesic6a86652018-04-24 11:49:14 +0200142 mutex_lock(&hw->lock);
143
144 err = hw->tf->read(hw->dev, ST_ASM330LHH_REG_FIFO_THL_ADDR + 1,
145 sizeof(data), &data);
146 if (err < 0)
147 goto out;
148
149 fifo_watermark = ((data << 8) & ~ST_ASM330LHH_REG_FIFO_LEN_MASK) |
150 (fifo_watermark & ST_ASM330LHH_REG_FIFO_LEN_MASK);
151 wdata = cpu_to_le16(fifo_watermark);
152 err = hw->tf->write(hw->dev, ST_ASM330LHH_REG_FIFO_THL_ADDR,
153 sizeof(wdata), (u8 *)&wdata);
154
155out:
156 mutex_unlock(&hw->lock);
157
158 return err < 0 ? err : 0;
159}
160
Mario Tesic6a86652018-04-24 11:49:14 +0200161static struct iio_dev *st_asm330lhh_get_iiodev_from_tag(struct st_asm330lhh_hw *hw,
162 u8 tag)
163{
164 struct iio_dev *iio_dev;
165
166 switch (tag) {
167 case ST_ASM330LHH_GYRO_TAG:
168 iio_dev = hw->iio_devs[ST_ASM330LHH_ID_GYRO];
169 break;
170 case ST_ASM330LHH_ACC_TAG:
171 iio_dev = hw->iio_devs[ST_ASM330LHH_ID_ACC];
172 break;
173 default:
174 iio_dev = NULL;
175 break;
176 }
177
178 return iio_dev;
179}
Puneet yatnala80857e72018-03-07 17:30:49 +0530180#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING
181int asm330_check_acc_gyro_early_buff_enable_flag(
182 struct st_asm330lhh_sensor *sensor)
183{
184 if (sensor->buffer_asm_samples == true)
185 return 1;
186 else
187 return 0;
188}
189#else
190int asm330_check_acc_gyro_early_buff_enable_flag(
191 struct st_asm330lhh_sensor *sensor)
192{
193 return 0;
194}
195#endif
196
197#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING
198static void store_acc_gyro_boot_sample(struct st_asm330lhh_sensor *sensor,
199 u8 *iio_buf, s64 tsample)
200{
201 int x, y, z;
202
203 if (false == sensor->buffer_asm_samples)
204 return;
205
206 sensor->timestamp = (ktime_t)tsample;
207 x = iio_buf[1]<<8|iio_buf[0];
208 y = iio_buf[3]<<8|iio_buf[2];
209 z = iio_buf[5]<<8|iio_buf[4];
210
211 if (ktime_to_timespec(sensor->timestamp).tv_sec
212 < sensor->max_buffer_time) {
213 if (sensor->bufsample_cnt < ASM_MAXSAMPLE) {
214 sensor->asm_samplist[sensor->bufsample_cnt]->xyz[0] = x;
215 sensor->asm_samplist[sensor->bufsample_cnt]->xyz[1] = y;
216 sensor->asm_samplist[sensor->bufsample_cnt]->xyz[2] = z;
217 sensor->asm_samplist[sensor->bufsample_cnt]->tsec =
218 ktime_to_timespec(sensor->timestamp).tv_sec;
219 sensor->asm_samplist[sensor->bufsample_cnt]->tnsec =
220 ktime_to_timespec(sensor->timestamp).tv_nsec;
221 sensor->bufsample_cnt++;
222 }
223 } else {
224 dev_info(sensor->hw->dev, "End of sensor %d buffering %d\n",
225 sensor->id, sensor->bufsample_cnt);
226 sensor->buffer_asm_samples = false;
227 }
228}
229#else
230static void store_acc_gyro_boot_sample(struct st_asm330lhh_sensor *sensor,
231 u8 *iio_buf, s64 tsample)
232{
233}
234#endif
Mario Tesic6a86652018-04-24 11:49:14 +0200235
mario tesi547c2f52020-03-18 13:36:32 +0100236static inline void st_asm330lhh_sync_hw_ts(struct st_asm330lhh_hw *hw, s64 ts)
237{
238 s64 delta = ts - hw->hw_ts;
239
240 hw->ts_offset = st_asm330lhh_ewma(hw->ts_offset, delta,
241 ST_ASM330LHH_EWMA_LEVEL);
242}
243
Mario Tesic6a86652018-04-24 11:49:14 +0200244static int st_asm330lhh_read_fifo(struct st_asm330lhh_hw *hw)
245{
246 u8 iio_buf[ALIGN(ST_ASM330LHH_SAMPLE_SIZE, sizeof(s64)) + sizeof(s64)];
Puneet45a17442019-04-16 10:07:14 +0530247 u8 buf[30 * ST_ASM330LHH_FIFO_SAMPLE_SIZE], tag, *ptr;
mario tesi547c2f52020-03-18 13:36:32 +0100248 int i, err, word_len, fifo_len, read_len;
Mario Tesic6a86652018-04-24 11:49:14 +0200249 struct iio_dev *iio_dev;
mario tesi547c2f52020-03-18 13:36:32 +0100250 struct st_asm330lhh_sensor *sensor;
251 s64 ts_irq, hw_ts_old;
Mario Tesic6a86652018-04-24 11:49:14 +0200252 __le16 fifo_status;
253 u16 fifo_depth;
mario tesi547c2f52020-03-18 13:36:32 +0100254 s16 drdymask;
255 u32 val;
256
257 /* return if FIFO is already disabled */
258 if (!test_bit(ST_ASM330LHH_HW_OPERATIONAL, &hw->state)) {
259 dev_warn(hw->dev, "%s: FIFO in bypass mode\n", __func__);
260
261 return 0;
262 }
Mario Tesic6a86652018-04-24 11:49:14 +0200263
264 ts_irq = hw->ts - hw->delta_ts;
265
mario tesi547c2f52020-03-18 13:36:32 +0100266 err = st_asm330lhh_read_atomic(hw, ST_ASM330LHH_REG_FIFO_STATUS1_ADDR,
267 sizeof(fifo_status), (u8 *)&fifo_status);
268 if (err < 0)
269 return err;
270
271 fifo_depth = le16_to_cpu(fifo_status) &
272 ST_ASM330LHH_REG_FIFO_STATUS_DIFF;
273 if (!fifo_depth)
274 return 0;
275
276 fifo_len = fifo_depth * ST_ASM330LHH_FIFO_SAMPLE_SIZE;
277 read_len = 0;
278 while (read_len < fifo_len) {
279 word_len = min_t(int, fifo_len - read_len, sizeof(buf));
280 err = st_asm330lhh_read_atomic(hw,
281 ST_ASM330LHH_REG_FIFO_OUT_TAG_ADDR,
282 word_len, buf);
Mario Tesic6a86652018-04-24 11:49:14 +0200283 if (err < 0)
284 return err;
mario tesi547c2f52020-03-18 13:36:32 +0100285 for (i = 0; i < word_len; i += ST_ASM330LHH_FIFO_SAMPLE_SIZE) {
286 ptr = &buf[i + ST_ASM330LHH_TAG_SIZE];
287 tag = buf[i] >> 3;
Mario Tesic6a86652018-04-24 11:49:14 +0200288
mario tesi547c2f52020-03-18 13:36:32 +0100289 if (tag == ST_ASM330LHH_TS_TAG) {
290 val = get_unaligned_le32(ptr);
Mario Tesic6a86652018-04-24 11:49:14 +0200291
mario tesi547c2f52020-03-18 13:36:32 +0100292 if (hw->val_ts_old > val)
293 hw->hw_ts_high++;
Mario Tesic6a86652018-04-24 11:49:14 +0200294
mario tesi547c2f52020-03-18 13:36:32 +0100295 hw_ts_old = hw->hw_ts;
Mario Tesi98ce0b82019-11-25 15:30:12 +0100296
mario tesi547c2f52020-03-18 13:36:32 +0100297 /* check hw rollover */
298 hw->val_ts_old = val;
299 hw->hw_ts = (val + ((s64)hw->hw_ts_high <<
300 32)) * hw->ts_delta_ns;
301 hw->ts_offset = st_asm330lhh_ewma(hw->ts_offset,
302 ts_irq - hw->hw_ts,
303 ST_ASM330LHH_EWMA_LEVEL);
Mario Tesic6a86652018-04-24 11:49:14 +0200304
mario tesi547c2f52020-03-18 13:36:32 +0100305 if (!test_bit(ST_ASM330LHH_HW_FLUSH,
306 &hw->state))
307 /* sync ap timestamp and sensor one */
308 st_asm330lhh_sync_hw_ts(hw, ts_irq);
Mario Tesic6a86652018-04-24 11:49:14 +0200309
mario tesi547c2f52020-03-18 13:36:32 +0100310 ts_irq += hw->hw_ts;
Mario Tesic6a86652018-04-24 11:49:14 +0200311
mario tesi547c2f52020-03-18 13:36:32 +0100312 if (!hw->tsample)
313 hw->tsample = hw->ts_offset + hw->hw_ts;
314 else
315 hw->tsample = hw->tsample +
316 hw->hw_ts - hw_ts_old;
317 } else {
318 iio_dev = st_asm330lhh_get_iiodev_from_tag(hw,
319 tag);
320 if (!iio_dev)
321 continue;
322 sensor = iio_priv(iio_dev);
Mario Tesic6a86652018-04-24 11:49:14 +0200323
mario tesi547c2f52020-03-18 13:36:32 +0100324 /* skip samples if not ready */
325 drdymask = (s16)le16_to_cpu(
326 get_unaligned_le16(ptr));
327 if (unlikely(drdymask
328 >= ST_ASM330LHH_SAMPLE_DISCHARD)) {
329 continue;
Mario Tesic6a86652018-04-24 11:49:14 +0200330 }
mario tesi547c2f52020-03-18 13:36:32 +0100331 memcpy(iio_buf, ptr, ST_ASM330LHH_SAMPLE_SIZE);
332
333 hw->tsample = min_t(s64,
334 hw->ts,
335 hw->tsample);
336
337 iio_push_to_buffers_with_timestamp(iio_dev,
338 iio_buf,
339 hw->tsample);
Puneet Yatnal3cbaa6f2020-01-08 18:09:41 +0530340 mutex_lock(&sensor->sensor_buff);
mario tesi547c2f52020-03-18 13:36:32 +0100341 store_acc_gyro_boot_sample(sensor,
342 iio_buf, hw->tsample);
Puneet Yatnal3cbaa6f2020-01-08 18:09:41 +0530343 mutex_unlock(&sensor->sensor_buff);
mario tesi547c2f52020-03-18 13:36:32 +0100344 }
345 }
346 read_len += word_len;
347 }
Mario Tesic6a86652018-04-24 11:49:14 +0200348
349 return read_len;
350}
351
352ssize_t st_asm330lhh_get_max_watermark(struct device *dev,
353 struct device_attribute *attr, char *buf)
354{
355 return sprintf(buf, "%d\n", ST_ASM330LHH_MAX_FIFO_DEPTH);
356}
357
358ssize_t st_asm330lhh_get_watermark(struct device *dev,
359 struct device_attribute *attr, char *buf)
360{
361 struct iio_dev *iio_dev = dev_get_drvdata(dev);
362 struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
363
364 return sprintf(buf, "%d\n", sensor->watermark);
365}
366
367ssize_t st_asm330lhh_set_watermark(struct device *dev,
368 struct device_attribute *attr,
369 const char *buf, size_t size)
370{
371 struct iio_dev *iio_dev = dev_get_drvdata(dev);
372 struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
373 int err, val;
374
Puneet yatnala80857e72018-03-07 17:30:49 +0530375 if (asm330_check_acc_gyro_early_buff_enable_flag(sensor))
Puneet Yatnal8216ef62019-02-06 11:05:55 +0530376 return -EBUSY;
Puneet yatnala80857e72018-03-07 17:30:49 +0530377
Mario Tesic6a86652018-04-24 11:49:14 +0200378 mutex_lock(&iio_dev->mlock);
379 if (iio_buffer_enabled(iio_dev)) {
380 err = -EBUSY;
381 goto out;
382 }
383
384 err = kstrtoint(buf, 10, &val);
385 if (err < 0)
386 goto out;
387
388 err = st_asm330lhh_update_watermark(sensor, val);
389 if (err < 0)
390 goto out;
391
392 sensor->watermark = val;
393
394out:
395 mutex_unlock(&iio_dev->mlock);
396
397 return err < 0 ? err : size;
398}
399
400ssize_t st_asm330lhh_flush_fifo(struct device *dev,
401 struct device_attribute *attr,
402 const char *buf, size_t size)
403{
404 struct iio_dev *iio_dev = dev_get_drvdata(dev);
405 struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
406 struct st_asm330lhh_hw *hw = sensor->hw;
mario tesi547c2f52020-03-18 13:36:32 +0100407 s64 event;
Mario Tesic6a86652018-04-24 11:49:14 +0200408 int count;
mario tesi547c2f52020-03-18 13:36:32 +0100409 s64 type;
Mario Tesic6a86652018-04-24 11:49:14 +0200410 s64 ts;
411
412 mutex_lock(&hw->fifo_lock);
413 ts = st_asm330lhh_get_time_ns();
414 hw->delta_ts = ts - hw->ts;
415 hw->ts = ts;
416 set_bit(ST_ASM330LHH_HW_FLUSH, &hw->state);
Mario Tesic6a86652018-04-24 11:49:14 +0200417 count = st_asm330lhh_read_fifo(hw);
Mario Tesic6a86652018-04-24 11:49:14 +0200418 mutex_unlock(&hw->fifo_lock);
419
420 type = count > 0 ? CUSTOM_IIO_EV_DIR_FIFO_DATA : CUSTOM_IIO_EV_DIR_FIFO_EMPTY;
421 event = IIO_UNMOD_EVENT_CODE(iio_dev->channels[0].type, -1,
422 CUSTOM_IIO_EV_TYPE_FIFO_FLUSH, type);
423 iio_push_event(iio_dev, event, st_asm330lhh_get_time_ns());
424
425 return size;
426}
427
428int st_asm330lhh_suspend_fifo(struct st_asm330lhh_hw *hw)
429{
430 int err;
431
432 mutex_lock(&hw->fifo_lock);
Mario Tesic6a86652018-04-24 11:49:14 +0200433 st_asm330lhh_read_fifo(hw);
434 err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_BYPASS);
Mario Tesic6a86652018-04-24 11:49:14 +0200435 mutex_unlock(&hw->fifo_lock);
436
437 return err;
438}
439
Puneet yatnala80857e72018-03-07 17:30:49 +0530440int st_asm330lhh_update_fifo(struct iio_dev *iio_dev, bool enable)
Mario Tesic6a86652018-04-24 11:49:14 +0200441{
442 struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
443 struct st_asm330lhh_hw *hw = sensor->hw;
444 int err;
445
446 mutex_lock(&hw->fifo_lock);
447
448 err = st_asm330lhh_sensor_set_enable(sensor, enable);
449 if (err < 0)
450 goto out;
451
452 err = st_asm330lhh_set_sensor_batching_odr(sensor, enable);
453 if (err < 0)
454 goto out;
455
456 err = st_asm330lhh_update_watermark(sensor, sensor->watermark);
457 if (err < 0)
458 goto out;
459
Mario Tesic6a86652018-04-24 11:49:14 +0200460 if (enable && hw->fifo_mode == ST_ASM330LHH_FIFO_BYPASS) {
461 st_asm330lhh_reset_hwts(hw);
462 err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_CONT);
463 } else if (!hw->enable_mask) {
464 err = st_asm330lhh_set_fifo_mode(hw, ST_ASM330LHH_FIFO_BYPASS);
465 }
466
467out:
468 mutex_unlock(&hw->fifo_lock);
469
470 return err;
471}
472
473static irqreturn_t st_asm330lhh_handler_irq(int irq, void *private)
474{
475 struct st_asm330lhh_hw *hw = (struct st_asm330lhh_hw *)private;
476 s64 ts = st_asm330lhh_get_time_ns();
477
478 hw->delta_ts = ts - hw->ts;
479 hw->ts = ts;
480
Puneet Yatnalef8d7652020-03-19 09:57:34 +0530481 if (hw->asm330_hrtimer)
482 st_asm330lhh_hrtimer_reset(hw, hw->delta_ts);
483
Mario Tesic6a86652018-04-24 11:49:14 +0200484 return IRQ_WAKE_THREAD;
485}
486
487static irqreturn_t st_asm330lhh_handler_thread(int irq, void *private)
488{
489 struct st_asm330lhh_hw *hw = (struct st_asm330lhh_hw *)private;
490
491 mutex_lock(&hw->fifo_lock);
Mario Tesic6a86652018-04-24 11:49:14 +0200492 st_asm330lhh_read_fifo(hw);
493 clear_bit(ST_ASM330LHH_HW_FLUSH, &hw->state);
Mario Tesic6a86652018-04-24 11:49:14 +0200494 mutex_unlock(&hw->fifo_lock);
495
Puneet Yatnalef8d7652020-03-19 09:57:34 +0530496 if (hw->asm330_hrtimer)
497 st_asm330lhh_set_cpu_idle_state(false);
498
Mario Tesic6a86652018-04-24 11:49:14 +0200499 return IRQ_HANDLED;
500}
501
502static int st_asm330lhh_buffer_preenable(struct iio_dev *iio_dev)
503{
Puneet yatnala80857e72018-03-07 17:30:49 +0530504 struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
Puneet yatnala80857e72018-03-07 17:30:49 +0530505
506 if (asm330_check_acc_gyro_early_buff_enable_flag(sensor))
Puneet Yatnal8216ef62019-02-06 11:05:55 +0530507 return 0;
Puneet yatnala80857e72018-03-07 17:30:49 +0530508 else
509 return st_asm330lhh_update_fifo(iio_dev, true);
Mario Tesic6a86652018-04-24 11:49:14 +0200510}
511
512static int st_asm330lhh_buffer_postdisable(struct iio_dev *iio_dev)
513{
Puneet yatnala80857e72018-03-07 17:30:49 +0530514 struct st_asm330lhh_sensor *sensor = iio_priv(iio_dev);
Puneet yatnala80857e72018-03-07 17:30:49 +0530515
516 if (asm330_check_acc_gyro_early_buff_enable_flag(sensor))
Puneet Yatnal8216ef62019-02-06 11:05:55 +0530517 return 0;
Puneet yatnala80857e72018-03-07 17:30:49 +0530518 else
519 return st_asm330lhh_update_fifo(iio_dev, false);
Mario Tesic6a86652018-04-24 11:49:14 +0200520}
521
522static const struct iio_buffer_setup_ops st_asm330lhh_buffer_ops = {
523 .preenable = st_asm330lhh_buffer_preenable,
524 .postdisable = st_asm330lhh_buffer_postdisable,
525};
526
527static int st_asm330lhh_fifo_init(struct st_asm330lhh_hw *hw)
528{
529 return st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_FIFO_CTRL4_ADDR,
530 ST_ASM330LHH_REG_DEC_TS_MASK, 1);
531}
532
533int st_asm330lhh_fifo_setup(struct st_asm330lhh_hw *hw)
534{
535 struct device_node *np = hw->dev->of_node;
536 struct iio_buffer *buffer;
537 unsigned long irq_type;
538 bool irq_active_low;
539 int i, err;
540
541 irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
mario tesi547c2f52020-03-18 13:36:32 +0100542 if (irq_type == IRQF_TRIGGER_NONE)
543 irq_type = IRQF_TRIGGER_HIGH;
Mario Tesic6a86652018-04-24 11:49:14 +0200544
545 switch (irq_type) {
546 case IRQF_TRIGGER_HIGH:
547 case IRQF_TRIGGER_RISING:
548 irq_active_low = false;
549 break;
550 case IRQF_TRIGGER_LOW:
551 case IRQF_TRIGGER_FALLING:
552 irq_active_low = true;
553 break;
554 default:
555 dev_info(hw->dev, "mode %lx unsupported\n", irq_type);
556 return -EINVAL;
557 }
558
559 err = st_asm330lhh_write_with_mask(hw, ST_ASM330LHH_REG_HLACTIVE_ADDR,
560 ST_ASM330LHH_REG_HLACTIVE_MASK,
561 irq_active_low);
562 if (err < 0)
563 return err;
564
565 if (np && of_property_read_bool(np, "drive-open-drain")) {
566 err = st_asm330lhh_write_with_mask(hw,
567 ST_ASM330LHH_REG_PP_OD_ADDR,
568 ST_ASM330LHH_REG_PP_OD_MASK, 1);
569 if (err < 0)
570 return err;
571
572 irq_type |= IRQF_SHARED;
573 }
574
575 err = devm_request_threaded_irq(hw->dev, hw->irq,
576 st_asm330lhh_handler_irq,
577 st_asm330lhh_handler_thread,
578 irq_type | IRQF_ONESHOT,
579 "asm330lhh", hw);
580 if (err) {
581 dev_err(hw->dev, "failed to request trigger irq %d\n",
582 hw->irq);
583 return err;
584 }
585
586 for (i = ST_ASM330LHH_ID_ACC; i < ST_ASM330LHH_ID_MAX; i++) {
587 if (!hw->iio_devs[i])
588 continue;
589
590 buffer = devm_iio_kfifo_allocate(hw->dev);
591 if (!buffer)
592 return -ENOMEM;
593
594 iio_device_attach_buffer(hw->iio_devs[i], buffer);
595 hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE;
596 hw->iio_devs[i]->setup_ops = &st_asm330lhh_buffer_ops;
597 }
598
599 return st_asm330lhh_fifo_init(hw);
600}