1fda8d26eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2290a6ce1SLorenzo Bianconi /*
3290a6ce1SLorenzo Bianconi * STMicroelectronics st_lsm6dsx FIFO buffer library driver
4290a6ce1SLorenzo Bianconi *
5dbcd2088SLorenzo Bianconi * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C:
6dbcd2088SLorenzo Bianconi * The FIFO buffer can be configured to store data from gyroscope and
7dbcd2088SLorenzo Bianconi * accelerometer. Samples are queued without any tag according to a
8dbcd2088SLorenzo Bianconi * specific pattern based on 'FIFO data sets' (6 bytes each):
9290a6ce1SLorenzo Bianconi * - 1st data set is reserved for gyroscope data
10290a6ce1SLorenzo Bianconi * - 2nd data set is reserved for accelerometer data
11290a6ce1SLorenzo Bianconi * The FIFO pattern changes depending on the ODRs and decimation factors
12290a6ce1SLorenzo Bianconi * assigned to the FIFO data sets. The first sequence of data stored in FIFO
13290a6ce1SLorenzo Bianconi * buffer contains the data of all the enabled FIFO data sets
14290a6ce1SLorenzo Bianconi * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
15290a6ce1SLorenzo Bianconi * value of the decimation factor and ODR set for each FIFO data set.
16801a6e0aSLorenzo Bianconi *
17fdd70d7aSLorenzo Bianconi * LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/LSM6DSRX/ISM330DHCX/
18*18462d08SLorenzo Bianconi * LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV/ASM330LHB:
19cf9c71b3SLorenzo Bianconi * The FIFO buffer can be configured to store data from gyroscope and
20cf9c71b3SLorenzo Bianconi * accelerometer. Each sample is queued with a tag (1B) indicating data
21cf9c71b3SLorenzo Bianconi * source (gyroscope, accelerometer, hw timer).
22801a6e0aSLorenzo Bianconi *
23290a6ce1SLorenzo Bianconi * FIFO supported modes:
24290a6ce1SLorenzo Bianconi * - BYPASS: FIFO disabled
25290a6ce1SLorenzo Bianconi * - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index
26290a6ce1SLorenzo Bianconi * restarts from the beginning and the oldest sample is overwritten
27290a6ce1SLorenzo Bianconi *
28290a6ce1SLorenzo Bianconi * Copyright 2016 STMicroelectronics Inc.
29290a6ce1SLorenzo Bianconi *
30290a6ce1SLorenzo Bianconi * Lorenzo Bianconi <lorenzo.bianconi@st.com>
31290a6ce1SLorenzo Bianconi * Denis Ciocca <denis.ciocca@st.com>
32290a6ce1SLorenzo Bianconi */
33290a6ce1SLorenzo Bianconi #include <linux/module.h>
34290a6ce1SLorenzo Bianconi #include <linux/iio/kfifo_buf.h>
35290a6ce1SLorenzo Bianconi #include <linux/iio/iio.h>
36290a6ce1SLorenzo Bianconi #include <linux/iio/buffer.h>
3751a8b707SLorenzo Bianconi #include <linux/regmap.h>
3851a8b707SLorenzo Bianconi #include <linux/bitfield.h>
39290a6ce1SLorenzo Bianconi
40ff5fff4aSLorenzo Bianconi #include <linux/platform_data/st_sensors_pdata.h>
41ff5fff4aSLorenzo Bianconi
42290a6ce1SLorenzo Bianconi #include "st_lsm6dsx.h"
43290a6ce1SLorenzo Bianconi
44290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_FIFO_MODE_ADDR 0x0a
45290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_FIFO_MODE_MASK GENMASK(2, 0)
46290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3)
47290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_FIFO_EMPTY_MASK BIT(12)
48290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_FIFO_OUTL_ADDR 0x3e
49801a6e0aSLorenzo Bianconi #define ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR 0x78
5021345107SLorenzo Bianconi #define ST_LSM6DSX_REG_TS_RESET_ADDR 0x42
51290a6ce1SLorenzo Bianconi
52290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08
53290a6ce1SLorenzo Bianconi
5421345107SLorenzo Bianconi #define ST_LSM6DSX_TS_RESET_VAL 0xaa
5521345107SLorenzo Bianconi
56290a6ce1SLorenzo Bianconi struct st_lsm6dsx_decimator_entry {
57290a6ce1SLorenzo Bianconi u8 decimator;
58290a6ce1SLorenzo Bianconi u8 val;
59290a6ce1SLorenzo Bianconi };
60290a6ce1SLorenzo Bianconi
61801a6e0aSLorenzo Bianconi enum st_lsm6dsx_fifo_tag {
62801a6e0aSLorenzo Bianconi ST_LSM6DSX_GYRO_TAG = 0x01,
63801a6e0aSLorenzo Bianconi ST_LSM6DSX_ACC_TAG = 0x02,
64801a6e0aSLorenzo Bianconi ST_LSM6DSX_TS_TAG = 0x04,
656d0205fdSLorenzo Bianconi ST_LSM6DSX_EXT0_TAG = 0x0f,
666d0205fdSLorenzo Bianconi ST_LSM6DSX_EXT1_TAG = 0x10,
676d0205fdSLorenzo Bianconi ST_LSM6DSX_EXT2_TAG = 0x11,
68801a6e0aSLorenzo Bianconi };
69801a6e0aSLorenzo Bianconi
70290a6ce1SLorenzo Bianconi static const
71290a6ce1SLorenzo Bianconi struct st_lsm6dsx_decimator_entry st_lsm6dsx_decimator_table[] = {
72290a6ce1SLorenzo Bianconi { 0, 0x0 },
73290a6ce1SLorenzo Bianconi { 1, 0x1 },
74290a6ce1SLorenzo Bianconi { 2, 0x2 },
75290a6ce1SLorenzo Bianconi { 3, 0x3 },
76290a6ce1SLorenzo Bianconi { 4, 0x4 },
77290a6ce1SLorenzo Bianconi { 8, 0x5 },
78290a6ce1SLorenzo Bianconi { 16, 0x6 },
79290a6ce1SLorenzo Bianconi { 32, 0x7 },
80290a6ce1SLorenzo Bianconi };
81290a6ce1SLorenzo Bianconi
825685b145SLorenzo Bianconi static int
st_lsm6dsx_get_decimator_val(struct st_lsm6dsx_sensor * sensor,u32 max_odr)835685b145SLorenzo Bianconi st_lsm6dsx_get_decimator_val(struct st_lsm6dsx_sensor *sensor, u32 max_odr)
84290a6ce1SLorenzo Bianconi {
85290a6ce1SLorenzo Bianconi const int max_size = ARRAY_SIZE(st_lsm6dsx_decimator_table);
865685b145SLorenzo Bianconi u32 decimator = max_odr / sensor->odr;
87290a6ce1SLorenzo Bianconi int i;
88290a6ce1SLorenzo Bianconi
895685b145SLorenzo Bianconi if (decimator > 1)
905685b145SLorenzo Bianconi decimator = round_down(decimator, 2);
915685b145SLorenzo Bianconi
925685b145SLorenzo Bianconi for (i = 0; i < max_size; i++) {
935685b145SLorenzo Bianconi if (st_lsm6dsx_decimator_table[i].decimator == decimator)
94290a6ce1SLorenzo Bianconi break;
955685b145SLorenzo Bianconi }
96290a6ce1SLorenzo Bianconi
977762902cSLorenzo Bianconi sensor->decimator = decimator;
98290a6ce1SLorenzo Bianconi return i == max_size ? 0 : st_lsm6dsx_decimator_table[i].val;
99290a6ce1SLorenzo Bianconi }
100290a6ce1SLorenzo Bianconi
st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw * hw,u32 * max_odr,u32 * min_odr)101290a6ce1SLorenzo Bianconi static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
102f8710f03SLorenzo Bianconi u32 *max_odr, u32 *min_odr)
103290a6ce1SLorenzo Bianconi {
104290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor;
105290a6ce1SLorenzo Bianconi int i;
106290a6ce1SLorenzo Bianconi
107290a6ce1SLorenzo Bianconi *max_odr = 0, *min_odr = ~0;
108290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
1096ffb55e5SLorenzo Bianconi if (!hw->iio_devs[i])
1106ffb55e5SLorenzo Bianconi continue;
1116ffb55e5SLorenzo Bianconi
112290a6ce1SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]);
113290a6ce1SLorenzo Bianconi
114290a6ce1SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id)))
115290a6ce1SLorenzo Bianconi continue;
116290a6ce1SLorenzo Bianconi
117f8710f03SLorenzo Bianconi *max_odr = max_t(u32, *max_odr, sensor->odr);
118f8710f03SLorenzo Bianconi *min_odr = min_t(u32, *min_odr, sensor->odr);
119290a6ce1SLorenzo Bianconi }
120290a6ce1SLorenzo Bianconi }
121290a6ce1SLorenzo Bianconi
st_lsm6dsx_get_sip(struct st_lsm6dsx_sensor * sensor,u32 min_odr)1225685b145SLorenzo Bianconi static u8 st_lsm6dsx_get_sip(struct st_lsm6dsx_sensor *sensor, u32 min_odr)
1235685b145SLorenzo Bianconi {
1245685b145SLorenzo Bianconi u8 sip = sensor->odr / min_odr;
1255685b145SLorenzo Bianconi
1265685b145SLorenzo Bianconi return sip > 1 ? round_down(sip, 2) : sip;
1275685b145SLorenzo Bianconi }
1285685b145SLorenzo Bianconi
st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw * hw)129290a6ce1SLorenzo Bianconi static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
130290a6ce1SLorenzo Bianconi {
13121345107SLorenzo Bianconi const struct st_lsm6dsx_reg *ts_dec_reg;
132290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor;
133f8710f03SLorenzo Bianconi u16 sip = 0, ts_sip = 0;
134f8710f03SLorenzo Bianconi u32 max_odr, min_odr;
13521345107SLorenzo Bianconi int err = 0, i;
136290a6ce1SLorenzo Bianconi u8 data;
137290a6ce1SLorenzo Bianconi
138290a6ce1SLorenzo Bianconi st_lsm6dsx_get_max_min_odr(hw, &max_odr, &min_odr);
139290a6ce1SLorenzo Bianconi
140290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
1417ca3ac9eSLorenzo Bianconi const struct st_lsm6dsx_reg *dec_reg;
142290a6ce1SLorenzo Bianconi
1436ffb55e5SLorenzo Bianconi if (!hw->iio_devs[i])
1446ffb55e5SLorenzo Bianconi continue;
1456ffb55e5SLorenzo Bianconi
1467ca3ac9eSLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]);
147290a6ce1SLorenzo Bianconi /* update fifo decimators and sample in pattern */
148290a6ce1SLorenzo Bianconi if (hw->enable_mask & BIT(sensor->id)) {
1495685b145SLorenzo Bianconi sensor->sip = st_lsm6dsx_get_sip(sensor, min_odr);
1505685b145SLorenzo Bianconi data = st_lsm6dsx_get_decimator_val(sensor, max_odr);
151290a6ce1SLorenzo Bianconi } else {
152290a6ce1SLorenzo Bianconi sensor->sip = 0;
153290a6ce1SLorenzo Bianconi data = 0;
154290a6ce1SLorenzo Bianconi }
15521345107SLorenzo Bianconi ts_sip = max_t(u16, ts_sip, sensor->sip);
156290a6ce1SLorenzo Bianconi
1577ca3ac9eSLorenzo Bianconi dec_reg = &hw->settings->decimator[sensor->id];
1587ca3ac9eSLorenzo Bianconi if (dec_reg->addr) {
15951a8b707SLorenzo Bianconi int val = ST_LSM6DSX_SHIFT_VAL(data, dec_reg->mask);
16051a8b707SLorenzo Bianconi
161739aff87SLorenzo Bianconi err = st_lsm6dsx_update_bits_locked(hw, dec_reg->addr,
162739aff87SLorenzo Bianconi dec_reg->mask,
163739aff87SLorenzo Bianconi val);
164290a6ce1SLorenzo Bianconi if (err < 0)
165290a6ce1SLorenzo Bianconi return err;
1667ca3ac9eSLorenzo Bianconi }
167290a6ce1SLorenzo Bianconi sip += sensor->sip;
168290a6ce1SLorenzo Bianconi }
16921345107SLorenzo Bianconi hw->sip = sip + ts_sip;
17021345107SLorenzo Bianconi hw->ts_sip = ts_sip;
171290a6ce1SLorenzo Bianconi
17221345107SLorenzo Bianconi /*
17321345107SLorenzo Bianconi * update hw ts decimator if necessary. Decimator for hw timestamp
17421345107SLorenzo Bianconi * is always 1 or 0 in order to have a ts sample for each data
17521345107SLorenzo Bianconi * sample in FIFO
17621345107SLorenzo Bianconi */
17721345107SLorenzo Bianconi ts_dec_reg = &hw->settings->ts_settings.decimator;
17821345107SLorenzo Bianconi if (ts_dec_reg->addr) {
17921345107SLorenzo Bianconi int val, ts_dec = !!hw->ts_sip;
18021345107SLorenzo Bianconi
18121345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(ts_dec, ts_dec_reg->mask);
182739aff87SLorenzo Bianconi err = st_lsm6dsx_update_bits_locked(hw, ts_dec_reg->addr,
18321345107SLorenzo Bianconi ts_dec_reg->mask, val);
18421345107SLorenzo Bianconi }
18521345107SLorenzo Bianconi return err;
186290a6ce1SLorenzo Bianconi }
187290a6ce1SLorenzo Bianconi
st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw * hw,enum st_lsm6dsx_fifo_mode fifo_mode)188a1bab939SLorenzo Bianconi static int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
189290a6ce1SLorenzo Bianconi enum st_lsm6dsx_fifo_mode fifo_mode)
190290a6ce1SLorenzo Bianconi {
191739aff87SLorenzo Bianconi unsigned int data;
192290a6ce1SLorenzo Bianconi
193739aff87SLorenzo Bianconi data = FIELD_PREP(ST_LSM6DSX_FIFO_MODE_MASK, fifo_mode);
194c2686eb2SLorenzo Bianconi return st_lsm6dsx_update_bits_locked(hw, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
195739aff87SLorenzo Bianconi ST_LSM6DSX_FIFO_MODE_MASK, data);
196290a6ce1SLorenzo Bianconi }
197290a6ce1SLorenzo Bianconi
st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor * sensor,bool enable)198ff81a933SLorenzo Bianconi static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
199ff81a933SLorenzo Bianconi bool enable)
200ff81a933SLorenzo Bianconi {
201ff81a933SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw;
202801a6e0aSLorenzo Bianconi const struct st_lsm6dsx_reg *batch_reg;
203ff81a933SLorenzo Bianconi u8 data;
204ff81a933SLorenzo Bianconi
205801a6e0aSLorenzo Bianconi batch_reg = &hw->settings->batch[sensor->id];
206801a6e0aSLorenzo Bianconi if (batch_reg->addr) {
207801a6e0aSLorenzo Bianconi int val;
208801a6e0aSLorenzo Bianconi
209801a6e0aSLorenzo Bianconi if (enable) {
210801a6e0aSLorenzo Bianconi int err;
211801a6e0aSLorenzo Bianconi
212801a6e0aSLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, sensor->odr,
213801a6e0aSLorenzo Bianconi &data);
214801a6e0aSLorenzo Bianconi if (err < 0)
215801a6e0aSLorenzo Bianconi return err;
216801a6e0aSLorenzo Bianconi } else {
217801a6e0aSLorenzo Bianconi data = 0;
218801a6e0aSLorenzo Bianconi }
219801a6e0aSLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(data, batch_reg->mask);
220739aff87SLorenzo Bianconi return st_lsm6dsx_update_bits_locked(hw, batch_reg->addr,
221801a6e0aSLorenzo Bianconi batch_reg->mask, val);
222801a6e0aSLorenzo Bianconi } else {
223ff81a933SLorenzo Bianconi data = hw->enable_mask ? ST_LSM6DSX_MAX_FIFO_ODR_VAL : 0;
224739aff87SLorenzo Bianconi return st_lsm6dsx_update_bits_locked(hw,
225801a6e0aSLorenzo Bianconi ST_LSM6DSX_REG_FIFO_MODE_ADDR,
22651a8b707SLorenzo Bianconi ST_LSM6DSX_FIFO_ODR_MASK,
227801a6e0aSLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_FIFO_ODR_MASK,
228801a6e0aSLorenzo Bianconi data));
229801a6e0aSLorenzo Bianconi }
230ff81a933SLorenzo Bianconi }
231ff81a933SLorenzo Bianconi
st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor * sensor,u16 watermark)232290a6ce1SLorenzo Bianconi int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
233290a6ce1SLorenzo Bianconi {
234a13bf65fSLorenzo Bianconi u16 fifo_watermark = ~0, cur_watermark, fifo_th_mask;
235290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw;
236290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *cur_sensor;
23751a8b707SLorenzo Bianconi int i, err, data;
238290a6ce1SLorenzo Bianconi __le16 wdata;
239290a6ce1SLorenzo Bianconi
240a13bf65fSLorenzo Bianconi if (!hw->sip)
241a13bf65fSLorenzo Bianconi return 0;
242a13bf65fSLorenzo Bianconi
243290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
2446ffb55e5SLorenzo Bianconi if (!hw->iio_devs[i])
2456ffb55e5SLorenzo Bianconi continue;
2466ffb55e5SLorenzo Bianconi
247290a6ce1SLorenzo Bianconi cur_sensor = iio_priv(hw->iio_devs[i]);
248290a6ce1SLorenzo Bianconi
249290a6ce1SLorenzo Bianconi if (!(hw->enable_mask & BIT(cur_sensor->id)))
250290a6ce1SLorenzo Bianconi continue;
251290a6ce1SLorenzo Bianconi
252290a6ce1SLorenzo Bianconi cur_watermark = (cur_sensor == sensor) ? watermark
253290a6ce1SLorenzo Bianconi : cur_sensor->watermark;
254290a6ce1SLorenzo Bianconi
255290a6ce1SLorenzo Bianconi fifo_watermark = min_t(u16, fifo_watermark, cur_watermark);
256290a6ce1SLorenzo Bianconi }
257290a6ce1SLorenzo Bianconi
258a13bf65fSLorenzo Bianconi fifo_watermark = max_t(u16, fifo_watermark, hw->sip);
259a13bf65fSLorenzo Bianconi fifo_watermark = (fifo_watermark / hw->sip) * hw->sip;
26092617c15SLorenzo Bianconi fifo_watermark = fifo_watermark * hw->settings->fifo_ops.th_wl;
261290a6ce1SLorenzo Bianconi
262739aff87SLorenzo Bianconi mutex_lock(&hw->page_lock);
26351a8b707SLorenzo Bianconi err = regmap_read(hw->regmap, hw->settings->fifo_ops.fifo_th.addr + 1,
26451a8b707SLorenzo Bianconi &data);
265290a6ce1SLorenzo Bianconi if (err < 0)
266739aff87SLorenzo Bianconi goto out;
267290a6ce1SLorenzo Bianconi
26892617c15SLorenzo Bianconi fifo_th_mask = hw->settings->fifo_ops.fifo_th.mask;
26992617c15SLorenzo Bianconi fifo_watermark = ((data << 8) & ~fifo_th_mask) |
27092617c15SLorenzo Bianconi (fifo_watermark & fifo_th_mask);
271290a6ce1SLorenzo Bianconi
272290a6ce1SLorenzo Bianconi wdata = cpu_to_le16(fifo_watermark);
273739aff87SLorenzo Bianconi err = regmap_bulk_write(hw->regmap,
27451a8b707SLorenzo Bianconi hw->settings->fifo_ops.fifo_th.addr,
27551a8b707SLorenzo Bianconi &wdata, sizeof(wdata));
276739aff87SLorenzo Bianconi out:
277739aff87SLorenzo Bianconi mutex_unlock(&hw->page_lock);
278739aff87SLorenzo Bianconi return err;
27951a8b707SLorenzo Bianconi }
280290a6ce1SLorenzo Bianconi
st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw * hw)28121345107SLorenzo Bianconi static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
28221345107SLorenzo Bianconi {
28321345107SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor;
28421345107SLorenzo Bianconi int i, err;
28521345107SLorenzo Bianconi
28621345107SLorenzo Bianconi /* reset hw ts counter */
287739aff87SLorenzo Bianconi err = st_lsm6dsx_write_locked(hw, ST_LSM6DSX_REG_TS_RESET_ADDR,
28821345107SLorenzo Bianconi ST_LSM6DSX_TS_RESET_VAL);
28921345107SLorenzo Bianconi if (err < 0)
29021345107SLorenzo Bianconi return err;
29121345107SLorenzo Bianconi
29221345107SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
2936ffb55e5SLorenzo Bianconi if (!hw->iio_devs[i])
2946ffb55e5SLorenzo Bianconi continue;
2956ffb55e5SLorenzo Bianconi
29621345107SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]);
29721345107SLorenzo Bianconi /*
29821345107SLorenzo Bianconi * store enable buffer timestamp as reference for
29921345107SLorenzo Bianconi * hw timestamp
30021345107SLorenzo Bianconi */
30121345107SLorenzo Bianconi sensor->ts_ref = iio_get_time_ns(hw->iio_devs[i]);
30221345107SLorenzo Bianconi }
30321345107SLorenzo Bianconi return 0;
30421345107SLorenzo Bianconi }
30521345107SLorenzo Bianconi
st_lsm6dsx_resume_fifo(struct st_lsm6dsx_hw * hw)306a1bab939SLorenzo Bianconi int st_lsm6dsx_resume_fifo(struct st_lsm6dsx_hw *hw)
307a1bab939SLorenzo Bianconi {
308a1bab939SLorenzo Bianconi int err;
309a1bab939SLorenzo Bianconi
310a1bab939SLorenzo Bianconi /* reset hw ts counter */
311a1bab939SLorenzo Bianconi err = st_lsm6dsx_reset_hw_ts(hw);
312a1bab939SLorenzo Bianconi if (err < 0)
313a1bab939SLorenzo Bianconi return err;
314a1bab939SLorenzo Bianconi
315a1bab939SLorenzo Bianconi return st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
316a1bab939SLorenzo Bianconi }
317a1bab939SLorenzo Bianconi
31851a8b707SLorenzo Bianconi /*
319801a6e0aSLorenzo Bianconi * Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN/ST_LSM6DSX_MAX_TAGGED_WORD_LEN
320801a6e0aSLorenzo Bianconi * in order to avoid a kmalloc for each bus access
32151a8b707SLorenzo Bianconi */
st_lsm6dsx_read_block(struct st_lsm6dsx_hw * hw,u8 addr,u8 * data,unsigned int data_len,unsigned int max_word_len)3225b3c87fdSLorenzo Bianconi static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr,
3235b3c87fdSLorenzo Bianconi u8 *data, unsigned int data_len,
3245b3c87fdSLorenzo Bianconi unsigned int max_word_len)
32551a8b707SLorenzo Bianconi {
32651a8b707SLorenzo Bianconi unsigned int word_len, read_len = 0;
32751a8b707SLorenzo Bianconi int err;
32851a8b707SLorenzo Bianconi
32951a8b707SLorenzo Bianconi while (read_len < data_len) {
33051a8b707SLorenzo Bianconi word_len = min_t(unsigned int, data_len - read_len,
3315b3c87fdSLorenzo Bianconi max_word_len);
332739aff87SLorenzo Bianconi err = st_lsm6dsx_read_locked(hw, addr, data + read_len,
3335b3c87fdSLorenzo Bianconi word_len);
33451a8b707SLorenzo Bianconi if (err < 0)
33551a8b707SLorenzo Bianconi return err;
33651a8b707SLorenzo Bianconi read_len += word_len;
33751a8b707SLorenzo Bianconi }
33851a8b707SLorenzo Bianconi return 0;
339290a6ce1SLorenzo Bianconi }
340290a6ce1SLorenzo Bianconi
34121345107SLorenzo Bianconi #define ST_LSM6DSX_IIO_BUFF_SIZE (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \
34221345107SLorenzo Bianconi sizeof(s64)) + sizeof(s64))
343290a6ce1SLorenzo Bianconi /**
344179c8d60SLorenzo Bianconi * st_lsm6dsx_read_fifo() - hw FIFO read routine
345290a6ce1SLorenzo Bianconi * @hw: Pointer to instance of struct st_lsm6dsx_hw.
346290a6ce1SLorenzo Bianconi *
347290a6ce1SLorenzo Bianconi * Read samples from the hw FIFO and push them to IIO buffers.
348290a6ce1SLorenzo Bianconi *
349290a6ce1SLorenzo Bianconi * Return: Number of bytes read from the FIFO
350290a6ce1SLorenzo Bianconi */
st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw * hw)35150ff457dSLorenzo Bianconi int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
352290a6ce1SLorenzo Bianconi {
353e485e2a2SLorenzo Bianconi struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor, *ext_sensor = NULL;
3547762902cSLorenzo Bianconi int err, sip, acc_sip, gyro_sip, ts_sip, ext_sip, read_len, offset;
355290a6ce1SLorenzo Bianconi u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
35692617c15SLorenzo Bianconi u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
35721345107SLorenzo Bianconi bool reset_ts = false;
358290a6ce1SLorenzo Bianconi __le16 fifo_status;
35921345107SLorenzo Bianconi s64 ts = 0;
360290a6ce1SLorenzo Bianconi
361739aff87SLorenzo Bianconi err = st_lsm6dsx_read_locked(hw,
36251a8b707SLorenzo Bianconi hw->settings->fifo_ops.fifo_diff.addr,
36351a8b707SLorenzo Bianconi &fifo_status, sizeof(fifo_status));
364a4217498SLorenzo Bianconi if (err < 0) {
365a4217498SLorenzo Bianconi dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
366a4217498SLorenzo Bianconi err);
367290a6ce1SLorenzo Bianconi return err;
368a4217498SLorenzo Bianconi }
369290a6ce1SLorenzo Bianconi
370290a6ce1SLorenzo Bianconi if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK))
371290a6ce1SLorenzo Bianconi return 0;
372290a6ce1SLorenzo Bianconi
37392617c15SLorenzo Bianconi fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) *
374290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHAN_SIZE;
375290a6ce1SLorenzo Bianconi fifo_len = (fifo_len / pattern_len) * pattern_len;
376290a6ce1SLorenzo Bianconi
377290a6ce1SLorenzo Bianconi acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
378290a6ce1SLorenzo Bianconi gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
379e485e2a2SLorenzo Bianconi if (hw->iio_devs[ST_LSM6DSX_ID_EXT0])
380e485e2a2SLorenzo Bianconi ext_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_EXT0]);
381290a6ce1SLorenzo Bianconi
382290a6ce1SLorenzo Bianconi for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
3835b3c87fdSLorenzo Bianconi err = st_lsm6dsx_read_block(hw, ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
3845b3c87fdSLorenzo Bianconi hw->buff, pattern_len,
3855b3c87fdSLorenzo Bianconi ST_LSM6DSX_MAX_WORD_LEN);
386a4217498SLorenzo Bianconi if (err < 0) {
387a4217498SLorenzo Bianconi dev_err(hw->dev,
388a4217498SLorenzo Bianconi "failed to read pattern from fifo (err=%d)\n",
389a4217498SLorenzo Bianconi err);
390290a6ce1SLorenzo Bianconi return err;
391a4217498SLorenzo Bianconi }
392290a6ce1SLorenzo Bianconi
393290a6ce1SLorenzo Bianconi /*
394290a6ce1SLorenzo Bianconi * Data are written to the FIFO with a specific pattern
395290a6ce1SLorenzo Bianconi * depending on the configured ODRs. The first sequence of data
396290a6ce1SLorenzo Bianconi * stored in FIFO contains the data of all enabled sensors
39721345107SLorenzo Bianconi * (e.g. Gx, Gy, Gz, Ax, Ay, Az, Ts), then data are repeated
398290a6ce1SLorenzo Bianconi * depending on the value of the decimation factor set for each
399290a6ce1SLorenzo Bianconi * sensor.
400290a6ce1SLorenzo Bianconi *
401290a6ce1SLorenzo Bianconi * Supposing the FIFO is storing data from gyroscope and
402290a6ce1SLorenzo Bianconi * accelerometer at different ODRs:
403290a6ce1SLorenzo Bianconi * - gyroscope ODR = 208Hz, accelerometer ODR = 104Hz
404290a6ce1SLorenzo Bianconi * Since the gyroscope ODR is twice the accelerometer one, the
405290a6ce1SLorenzo Bianconi * following pattern is repeated every 9 samples:
40621345107SLorenzo Bianconi * - Gx, Gy, Gz, Ax, Ay, Az, Ts, Gx, Gy, Gz, Ts, Gx, ..
407290a6ce1SLorenzo Bianconi */
408e485e2a2SLorenzo Bianconi ext_sip = ext_sensor ? ext_sensor->sip : 0;
409290a6ce1SLorenzo Bianconi gyro_sip = gyro_sensor->sip;
410290a6ce1SLorenzo Bianconi acc_sip = acc_sensor->sip;
41121345107SLorenzo Bianconi ts_sip = hw->ts_sip;
412290a6ce1SLorenzo Bianconi offset = 0;
4137762902cSLorenzo Bianconi sip = 0;
414290a6ce1SLorenzo Bianconi
415e485e2a2SLorenzo Bianconi while (acc_sip > 0 || gyro_sip > 0 || ext_sip > 0) {
4167762902cSLorenzo Bianconi if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) {
417c14edb4dSJonathan Cameron memcpy(hw->scan[ST_LSM6DSX_ID_GYRO].channels,
418c14edb4dSJonathan Cameron &hw->buff[offset],
419c14edb4dSJonathan Cameron sizeof(hw->scan[ST_LSM6DSX_ID_GYRO].channels));
420c14edb4dSJonathan Cameron offset += sizeof(hw->scan[ST_LSM6DSX_ID_GYRO].channels);
42121345107SLorenzo Bianconi }
4227762902cSLorenzo Bianconi if (acc_sip > 0 && !(sip % acc_sensor->decimator)) {
423c14edb4dSJonathan Cameron memcpy(hw->scan[ST_LSM6DSX_ID_ACC].channels,
424c14edb4dSJonathan Cameron &hw->buff[offset],
425c14edb4dSJonathan Cameron sizeof(hw->scan[ST_LSM6DSX_ID_ACC].channels));
426c14edb4dSJonathan Cameron offset += sizeof(hw->scan[ST_LSM6DSX_ID_ACC].channels);
42721345107SLorenzo Bianconi }
4287762902cSLorenzo Bianconi if (ext_sip > 0 && !(sip % ext_sensor->decimator)) {
429c14edb4dSJonathan Cameron memcpy(hw->scan[ST_LSM6DSX_ID_EXT0].channels,
430c14edb4dSJonathan Cameron &hw->buff[offset],
431c14edb4dSJonathan Cameron sizeof(hw->scan[ST_LSM6DSX_ID_EXT0].channels));
432c14edb4dSJonathan Cameron offset += sizeof(hw->scan[ST_LSM6DSX_ID_EXT0].channels);
433e485e2a2SLorenzo Bianconi }
43421345107SLorenzo Bianconi
43521345107SLorenzo Bianconi if (ts_sip-- > 0) {
43621345107SLorenzo Bianconi u8 data[ST_LSM6DSX_SAMPLE_SIZE];
43721345107SLorenzo Bianconi
43821345107SLorenzo Bianconi memcpy(data, &hw->buff[offset], sizeof(data));
43921345107SLorenzo Bianconi /*
44021345107SLorenzo Bianconi * hw timestamp is 3B long and it is stored
44121345107SLorenzo Bianconi * in FIFO using 6B as 4th FIFO data set
44221345107SLorenzo Bianconi * according to this schema:
44321345107SLorenzo Bianconi * B0 = ts[15:8], B1 = ts[23:16], B3 = ts[7:0]
44421345107SLorenzo Bianconi */
44521345107SLorenzo Bianconi ts = data[1] << 16 | data[0] << 8 | data[3];
44621345107SLorenzo Bianconi /*
44721345107SLorenzo Bianconi * check if hw timestamp engine is going to
44821345107SLorenzo Bianconi * reset (the sensor generates an interrupt
44921345107SLorenzo Bianconi * to signal the hw timestamp will reset in
45021345107SLorenzo Bianconi * 1.638s)
45121345107SLorenzo Bianconi */
45221345107SLorenzo Bianconi if (!reset_ts && ts >= 0xff0000)
45321345107SLorenzo Bianconi reset_ts = true;
454cb3b6b8eSMario Tesi ts *= hw->ts_gain;
45521345107SLorenzo Bianconi
45621345107SLorenzo Bianconi offset += ST_LSM6DSX_SAMPLE_SIZE;
45721345107SLorenzo Bianconi }
45821345107SLorenzo Bianconi
4597762902cSLorenzo Bianconi if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) {
460db3c4905SLorenzo Bianconi /*
461db3c4905SLorenzo Bianconi * We need to discards gyro samples during
462db3c4905SLorenzo Bianconi * filters settling time
463db3c4905SLorenzo Bianconi */
464db3c4905SLorenzo Bianconi if (gyro_sensor->samples_to_discard > 0)
465db3c4905SLorenzo Bianconi gyro_sensor->samples_to_discard--;
466db3c4905SLorenzo Bianconi else
467290a6ce1SLorenzo Bianconi iio_push_to_buffers_with_timestamp(
468290a6ce1SLorenzo Bianconi hw->iio_devs[ST_LSM6DSX_ID_GYRO],
469c14edb4dSJonathan Cameron &hw->scan[ST_LSM6DSX_ID_GYRO],
470c14edb4dSJonathan Cameron gyro_sensor->ts_ref + ts);
4717762902cSLorenzo Bianconi gyro_sip--;
4727762902cSLorenzo Bianconi }
4737762902cSLorenzo Bianconi if (acc_sip > 0 && !(sip % acc_sensor->decimator)) {
474db3c4905SLorenzo Bianconi /*
475db3c4905SLorenzo Bianconi * We need to discards accel samples during
476db3c4905SLorenzo Bianconi * filters settling time
477db3c4905SLorenzo Bianconi */
478db3c4905SLorenzo Bianconi if (acc_sensor->samples_to_discard > 0)
479db3c4905SLorenzo Bianconi acc_sensor->samples_to_discard--;
480db3c4905SLorenzo Bianconi else
481290a6ce1SLorenzo Bianconi iio_push_to_buffers_with_timestamp(
482290a6ce1SLorenzo Bianconi hw->iio_devs[ST_LSM6DSX_ID_ACC],
483c14edb4dSJonathan Cameron &hw->scan[ST_LSM6DSX_ID_ACC],
484c14edb4dSJonathan Cameron acc_sensor->ts_ref + ts);
4857762902cSLorenzo Bianconi acc_sip--;
4867762902cSLorenzo Bianconi }
4877762902cSLorenzo Bianconi if (ext_sip > 0 && !(sip % ext_sensor->decimator)) {
488e485e2a2SLorenzo Bianconi iio_push_to_buffers_with_timestamp(
489e485e2a2SLorenzo Bianconi hw->iio_devs[ST_LSM6DSX_ID_EXT0],
490c14edb4dSJonathan Cameron &hw->scan[ST_LSM6DSX_ID_EXT0],
491c14edb4dSJonathan Cameron ext_sensor->ts_ref + ts);
4927762902cSLorenzo Bianconi ext_sip--;
4937762902cSLorenzo Bianconi }
4947762902cSLorenzo Bianconi sip++;
495290a6ce1SLorenzo Bianconi }
496290a6ce1SLorenzo Bianconi }
497290a6ce1SLorenzo Bianconi
49821345107SLorenzo Bianconi if (unlikely(reset_ts)) {
49921345107SLorenzo Bianconi err = st_lsm6dsx_reset_hw_ts(hw);
500a4217498SLorenzo Bianconi if (err < 0) {
501a4217498SLorenzo Bianconi dev_err(hw->dev, "failed to reset hw ts (err=%d)\n",
502a4217498SLorenzo Bianconi err);
50321345107SLorenzo Bianconi return err;
50421345107SLorenzo Bianconi }
505a4217498SLorenzo Bianconi }
506290a6ce1SLorenzo Bianconi return read_len;
507290a6ce1SLorenzo Bianconi }
508290a6ce1SLorenzo Bianconi
509960506edSLorenzo Bianconi #define ST_LSM6DSX_INVALID_SAMPLE 0x7ffd
51014c7c6e1SLorenzo Bianconi static int
st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw * hw,u8 tag,u8 * data,s64 ts)51114c7c6e1SLorenzo Bianconi st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag,
51214c7c6e1SLorenzo Bianconi u8 *data, s64 ts)
51314c7c6e1SLorenzo Bianconi {
514960506edSLorenzo Bianconi s16 val = le16_to_cpu(*(__le16 *)data);
51514c7c6e1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor;
51614c7c6e1SLorenzo Bianconi struct iio_dev *iio_dev;
51714c7c6e1SLorenzo Bianconi
518960506edSLorenzo Bianconi /* invalid sample during bootstrap phase */
519960506edSLorenzo Bianconi if (val >= ST_LSM6DSX_INVALID_SAMPLE)
520960506edSLorenzo Bianconi return -EINVAL;
521960506edSLorenzo Bianconi
5226d0205fdSLorenzo Bianconi /*
5236d0205fdSLorenzo Bianconi * EXT_TAG are managed in FIFO fashion so ST_LSM6DSX_EXT0_TAG
5246d0205fdSLorenzo Bianconi * corresponds to the first enabled channel, ST_LSM6DSX_EXT1_TAG
5256d0205fdSLorenzo Bianconi * to the second one and ST_LSM6DSX_EXT2_TAG to the last enabled
5266d0205fdSLorenzo Bianconi * channel
5276d0205fdSLorenzo Bianconi */
52814c7c6e1SLorenzo Bianconi switch (tag) {
52914c7c6e1SLorenzo Bianconi case ST_LSM6DSX_GYRO_TAG:
53014c7c6e1SLorenzo Bianconi iio_dev = hw->iio_devs[ST_LSM6DSX_ID_GYRO];
53114c7c6e1SLorenzo Bianconi break;
53214c7c6e1SLorenzo Bianconi case ST_LSM6DSX_ACC_TAG:
53314c7c6e1SLorenzo Bianconi iio_dev = hw->iio_devs[ST_LSM6DSX_ID_ACC];
53414c7c6e1SLorenzo Bianconi break;
5356d0205fdSLorenzo Bianconi case ST_LSM6DSX_EXT0_TAG:
5366d0205fdSLorenzo Bianconi if (hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT0))
5376d0205fdSLorenzo Bianconi iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT0];
5386d0205fdSLorenzo Bianconi else if (hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT1))
5396d0205fdSLorenzo Bianconi iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT1];
5406d0205fdSLorenzo Bianconi else
5416d0205fdSLorenzo Bianconi iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
5426d0205fdSLorenzo Bianconi break;
5436d0205fdSLorenzo Bianconi case ST_LSM6DSX_EXT1_TAG:
5446d0205fdSLorenzo Bianconi if ((hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT0)) &&
5456d0205fdSLorenzo Bianconi (hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT1)))
5466d0205fdSLorenzo Bianconi iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT1];
5476d0205fdSLorenzo Bianconi else
5486d0205fdSLorenzo Bianconi iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
5496d0205fdSLorenzo Bianconi break;
5506d0205fdSLorenzo Bianconi case ST_LSM6DSX_EXT2_TAG:
5516d0205fdSLorenzo Bianconi iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
5526d0205fdSLorenzo Bianconi break;
55314c7c6e1SLorenzo Bianconi default:
55414c7c6e1SLorenzo Bianconi return -EINVAL;
55514c7c6e1SLorenzo Bianconi }
55614c7c6e1SLorenzo Bianconi
55714c7c6e1SLorenzo Bianconi sensor = iio_priv(iio_dev);
55814c7c6e1SLorenzo Bianconi iio_push_to_buffers_with_timestamp(iio_dev, data,
55914c7c6e1SLorenzo Bianconi ts + sensor->ts_ref);
56014c7c6e1SLorenzo Bianconi
56114c7c6e1SLorenzo Bianconi return 0;
56214c7c6e1SLorenzo Bianconi }
56314c7c6e1SLorenzo Bianconi
564801a6e0aSLorenzo Bianconi /**
56543901008SLorenzo Bianconi * st_lsm6dsx_read_tagged_fifo() - tagged hw FIFO read routine
566801a6e0aSLorenzo Bianconi * @hw: Pointer to instance of struct st_lsm6dsx_hw.
567801a6e0aSLorenzo Bianconi *
568801a6e0aSLorenzo Bianconi * Read samples from the hw FIFO and push them to IIO buffers.
569801a6e0aSLorenzo Bianconi *
570801a6e0aSLorenzo Bianconi * Return: Number of bytes read from the FIFO
571801a6e0aSLorenzo Bianconi */
st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw * hw)572801a6e0aSLorenzo Bianconi int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
573801a6e0aSLorenzo Bianconi {
574801a6e0aSLorenzo Bianconi u16 pattern_len = hw->sip * ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
575801a6e0aSLorenzo Bianconi u16 fifo_len, fifo_diff_mask;
576c14edb4dSJonathan Cameron /*
577c14edb4dSJonathan Cameron * Alignment needed as this can ultimately be passed to a
578c14edb4dSJonathan Cameron * call to iio_push_to_buffers_with_timestamp() which
579c14edb4dSJonathan Cameron * must be passed a buffer that is aligned to 8 bytes so
580c14edb4dSJonathan Cameron * as to allow insertion of a naturally aligned timestamp.
581c14edb4dSJonathan Cameron */
582c14edb4dSJonathan Cameron u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE] __aligned(8);
583c14edb4dSJonathan Cameron u8 tag;
584801a6e0aSLorenzo Bianconi bool reset_ts = false;
585801a6e0aSLorenzo Bianconi int i, err, read_len;
586801a6e0aSLorenzo Bianconi __le16 fifo_status;
587801a6e0aSLorenzo Bianconi s64 ts = 0;
588801a6e0aSLorenzo Bianconi
589739aff87SLorenzo Bianconi err = st_lsm6dsx_read_locked(hw,
590801a6e0aSLorenzo Bianconi hw->settings->fifo_ops.fifo_diff.addr,
591801a6e0aSLorenzo Bianconi &fifo_status, sizeof(fifo_status));
592801a6e0aSLorenzo Bianconi if (err < 0) {
593801a6e0aSLorenzo Bianconi dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
594801a6e0aSLorenzo Bianconi err);
595801a6e0aSLorenzo Bianconi return err;
596801a6e0aSLorenzo Bianconi }
597801a6e0aSLorenzo Bianconi
598801a6e0aSLorenzo Bianconi fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
599801a6e0aSLorenzo Bianconi fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) *
600801a6e0aSLorenzo Bianconi ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
601801a6e0aSLorenzo Bianconi if (!fifo_len)
602801a6e0aSLorenzo Bianconi return 0;
603801a6e0aSLorenzo Bianconi
604801a6e0aSLorenzo Bianconi for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
605801a6e0aSLorenzo Bianconi err = st_lsm6dsx_read_block(hw,
606801a6e0aSLorenzo Bianconi ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR,
607801a6e0aSLorenzo Bianconi hw->buff, pattern_len,
608801a6e0aSLorenzo Bianconi ST_LSM6DSX_MAX_TAGGED_WORD_LEN);
609801a6e0aSLorenzo Bianconi if (err < 0) {
610801a6e0aSLorenzo Bianconi dev_err(hw->dev,
611801a6e0aSLorenzo Bianconi "failed to read pattern from fifo (err=%d)\n",
612801a6e0aSLorenzo Bianconi err);
613801a6e0aSLorenzo Bianconi return err;
614801a6e0aSLorenzo Bianconi }
615801a6e0aSLorenzo Bianconi
616801a6e0aSLorenzo Bianconi for (i = 0; i < pattern_len;
617801a6e0aSLorenzo Bianconi i += ST_LSM6DSX_TAGGED_SAMPLE_SIZE) {
618801a6e0aSLorenzo Bianconi memcpy(iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE],
619801a6e0aSLorenzo Bianconi ST_LSM6DSX_SAMPLE_SIZE);
620801a6e0aSLorenzo Bianconi
621801a6e0aSLorenzo Bianconi tag = hw->buff[i] >> 3;
62214c7c6e1SLorenzo Bianconi if (tag == ST_LSM6DSX_TS_TAG) {
623801a6e0aSLorenzo Bianconi /*
624801a6e0aSLorenzo Bianconi * hw timestamp is 4B long and it is stored
625801a6e0aSLorenzo Bianconi * in FIFO according to this schema:
626801a6e0aSLorenzo Bianconi * B0 = ts[7:0], B1 = ts[15:8], B2 = ts[23:16],
627801a6e0aSLorenzo Bianconi * B3 = ts[31:24]
628801a6e0aSLorenzo Bianconi */
629801a6e0aSLorenzo Bianconi ts = le32_to_cpu(*((__le32 *)iio_buff));
630801a6e0aSLorenzo Bianconi /*
631801a6e0aSLorenzo Bianconi * check if hw timestamp engine is going to
632801a6e0aSLorenzo Bianconi * reset (the sensor generates an interrupt
633801a6e0aSLorenzo Bianconi * to signal the hw timestamp will reset in
634801a6e0aSLorenzo Bianconi * 1.638s)
635801a6e0aSLorenzo Bianconi */
636801a6e0aSLorenzo Bianconi if (!reset_ts && ts >= 0xffff0000)
637801a6e0aSLorenzo Bianconi reset_ts = true;
638cb3b6b8eSMario Tesi ts *= hw->ts_gain;
63914c7c6e1SLorenzo Bianconi } else {
64014c7c6e1SLorenzo Bianconi st_lsm6dsx_push_tagged_data(hw, tag, iio_buff,
64114c7c6e1SLorenzo Bianconi ts);
642801a6e0aSLorenzo Bianconi }
643801a6e0aSLorenzo Bianconi }
644801a6e0aSLorenzo Bianconi }
645801a6e0aSLorenzo Bianconi
646801a6e0aSLorenzo Bianconi if (unlikely(reset_ts)) {
647801a6e0aSLorenzo Bianconi err = st_lsm6dsx_reset_hw_ts(hw);
648801a6e0aSLorenzo Bianconi if (err < 0)
649801a6e0aSLorenzo Bianconi return err;
650801a6e0aSLorenzo Bianconi }
651801a6e0aSLorenzo Bianconi return read_len;
652801a6e0aSLorenzo Bianconi }
653801a6e0aSLorenzo Bianconi
st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw * hw)654535de397SLorenzo Bianconi int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
655290a6ce1SLorenzo Bianconi {
656290a6ce1SLorenzo Bianconi int err;
657290a6ce1SLorenzo Bianconi
658a912ee4cSLorenzo Bianconi if (!hw->settings->fifo_ops.read_fifo)
659a912ee4cSLorenzo Bianconi return -ENOTSUPP;
660a912ee4cSLorenzo Bianconi
661290a6ce1SLorenzo Bianconi mutex_lock(&hw->fifo_lock);
662290a6ce1SLorenzo Bianconi
66350ff457dSLorenzo Bianconi hw->settings->fifo_ops.read_fifo(hw);
664290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_BYPASS);
665290a6ce1SLorenzo Bianconi
666290a6ce1SLorenzo Bianconi mutex_unlock(&hw->fifo_lock);
667290a6ce1SLorenzo Bianconi
668290a6ce1SLorenzo Bianconi return err;
669290a6ce1SLorenzo Bianconi }
670290a6ce1SLorenzo Bianconi
671db3c4905SLorenzo Bianconi static void
st_lsm6dsx_update_samples_to_discard(struct st_lsm6dsx_sensor * sensor)672db3c4905SLorenzo Bianconi st_lsm6dsx_update_samples_to_discard(struct st_lsm6dsx_sensor *sensor)
673db3c4905SLorenzo Bianconi {
674db3c4905SLorenzo Bianconi const struct st_lsm6dsx_samples_to_discard *data;
675db3c4905SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw;
676db3c4905SLorenzo Bianconi int i;
677db3c4905SLorenzo Bianconi
678db3c4905SLorenzo Bianconi if (sensor->id != ST_LSM6DSX_ID_GYRO &&
679db3c4905SLorenzo Bianconi sensor->id != ST_LSM6DSX_ID_ACC)
680db3c4905SLorenzo Bianconi return;
681db3c4905SLorenzo Bianconi
682db3c4905SLorenzo Bianconi /* check if drdy mask is supported in hw */
683db3c4905SLorenzo Bianconi if (hw->settings->drdy_mask.addr)
684db3c4905SLorenzo Bianconi return;
685db3c4905SLorenzo Bianconi
686db3c4905SLorenzo Bianconi data = &hw->settings->samples_to_discard[sensor->id];
687db3c4905SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) {
688db3c4905SLorenzo Bianconi if (data->val[i].milli_hz == sensor->odr) {
689db3c4905SLorenzo Bianconi sensor->samples_to_discard = data->val[i].samples;
690db3c4905SLorenzo Bianconi return;
691db3c4905SLorenzo Bianconi }
692db3c4905SLorenzo Bianconi }
693db3c4905SLorenzo Bianconi }
694db3c4905SLorenzo Bianconi
st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor * sensor,bool enable)6953b72950dSLorenzo Bianconi int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable)
696290a6ce1SLorenzo Bianconi {
697290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw;
698c2686eb2SLorenzo Bianconi u8 fifo_mask;
699290a6ce1SLorenzo Bianconi int err;
700290a6ce1SLorenzo Bianconi
701335eaedcSLorenzo Bianconi mutex_lock(&hw->conf_lock);
702335eaedcSLorenzo Bianconi
703c2686eb2SLorenzo Bianconi if (enable)
704c2686eb2SLorenzo Bianconi fifo_mask = hw->fifo_mask | BIT(sensor->id);
705c2686eb2SLorenzo Bianconi else
706c2686eb2SLorenzo Bianconi fifo_mask = hw->fifo_mask & ~BIT(sensor->id);
707c2686eb2SLorenzo Bianconi
708c2686eb2SLorenzo Bianconi if (hw->fifo_mask) {
709290a6ce1SLorenzo Bianconi err = st_lsm6dsx_flush_fifo(hw);
710290a6ce1SLorenzo Bianconi if (err < 0)
711335eaedcSLorenzo Bianconi goto out;
712290a6ce1SLorenzo Bianconi }
713290a6ce1SLorenzo Bianconi
714db3c4905SLorenzo Bianconi if (enable)
715db3c4905SLorenzo Bianconi st_lsm6dsx_update_samples_to_discard(sensor);
716db3c4905SLorenzo Bianconi
717cd83c5c1SLorenzo Bianconi err = st_lsm6dsx_device_set_enable(sensor, enable);
7186d0205fdSLorenzo Bianconi if (err < 0)
7196d0205fdSLorenzo Bianconi goto out;
720290a6ce1SLorenzo Bianconi
721ff81a933SLorenzo Bianconi err = st_lsm6dsx_set_fifo_odr(sensor, enable);
722ff81a933SLorenzo Bianconi if (err < 0)
723335eaedcSLorenzo Bianconi goto out;
724ff81a933SLorenzo Bianconi
725290a6ce1SLorenzo Bianconi err = st_lsm6dsx_update_decimators(hw);
726290a6ce1SLorenzo Bianconi if (err < 0)
727335eaedcSLorenzo Bianconi goto out;
728290a6ce1SLorenzo Bianconi
729290a6ce1SLorenzo Bianconi err = st_lsm6dsx_update_watermark(sensor, sensor->watermark);
730290a6ce1SLorenzo Bianconi if (err < 0)
731335eaedcSLorenzo Bianconi goto out;
732290a6ce1SLorenzo Bianconi
733c2686eb2SLorenzo Bianconi if (fifo_mask) {
734a1bab939SLorenzo Bianconi err = st_lsm6dsx_resume_fifo(hw);
735c2686eb2SLorenzo Bianconi if (err < 0)
736c2686eb2SLorenzo Bianconi goto out;
737290a6ce1SLorenzo Bianconi }
738290a6ce1SLorenzo Bianconi
739c2686eb2SLorenzo Bianconi hw->fifo_mask = fifo_mask;
740c2686eb2SLorenzo Bianconi
741335eaedcSLorenzo Bianconi out:
742335eaedcSLorenzo Bianconi mutex_unlock(&hw->conf_lock);
743335eaedcSLorenzo Bianconi
744335eaedcSLorenzo Bianconi return err;
745290a6ce1SLorenzo Bianconi }
746290a6ce1SLorenzo Bianconi
st_lsm6dsx_buffer_preenable(struct iio_dev * iio_dev)747290a6ce1SLorenzo Bianconi static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev)
748290a6ce1SLorenzo Bianconi {
7493b72950dSLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
7503b72950dSLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw;
7513b72950dSLorenzo Bianconi
7523b72950dSLorenzo Bianconi if (!hw->settings->fifo_ops.update_fifo)
7533b72950dSLorenzo Bianconi return -ENOTSUPP;
7543b72950dSLorenzo Bianconi
7553b72950dSLorenzo Bianconi return hw->settings->fifo_ops.update_fifo(sensor, true);
756290a6ce1SLorenzo Bianconi }
757290a6ce1SLorenzo Bianconi
st_lsm6dsx_buffer_postdisable(struct iio_dev * iio_dev)758290a6ce1SLorenzo Bianconi static int st_lsm6dsx_buffer_postdisable(struct iio_dev *iio_dev)
759290a6ce1SLorenzo Bianconi {
7603b72950dSLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
7613b72950dSLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw;
7623b72950dSLorenzo Bianconi
7633b72950dSLorenzo Bianconi if (!hw->settings->fifo_ops.update_fifo)
7643b72950dSLorenzo Bianconi return -ENOTSUPP;
7653b72950dSLorenzo Bianconi
7663b72950dSLorenzo Bianconi return hw->settings->fifo_ops.update_fifo(sensor, false);
767290a6ce1SLorenzo Bianconi }
768290a6ce1SLorenzo Bianconi
769290a6ce1SLorenzo Bianconi static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = {
770290a6ce1SLorenzo Bianconi .preenable = st_lsm6dsx_buffer_preenable,
771290a6ce1SLorenzo Bianconi .postdisable = st_lsm6dsx_buffer_postdisable,
772290a6ce1SLorenzo Bianconi };
773290a6ce1SLorenzo Bianconi
st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw * hw)774290a6ce1SLorenzo Bianconi int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
775290a6ce1SLorenzo Bianconi {
77617395ce2SAlexandru Ardelean int i, ret;
777290a6ce1SLorenzo Bianconi
778290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
7796ffb55e5SLorenzo Bianconi if (!hw->iio_devs[i])
7806ffb55e5SLorenzo Bianconi continue;
7816ffb55e5SLorenzo Bianconi
78217395ce2SAlexandru Ardelean ret = devm_iio_kfifo_buffer_setup(hw->dev, hw->iio_devs[i],
78317395ce2SAlexandru Ardelean &st_lsm6dsx_buffer_ops);
78417395ce2SAlexandru Ardelean if (ret)
78517395ce2SAlexandru Ardelean return ret;
786290a6ce1SLorenzo Bianconi }
787290a6ce1SLorenzo Bianconi
788290a6ce1SLorenzo Bianconi return 0;
789290a6ce1SLorenzo Bianconi }
790