summaryrefslogtreecommitdiff
path: root/driver/accelgyro_lsm6dsm.h
blob: 51da2a42fbf80e90b704ed83a46b93a7ad660431 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
/* Copyright 2016 The ChromiumOS Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* LSM6DSM (also LSM6DSL) Accel and Gyro driver for Chrome EC */

#ifndef __CROS_EC_ACCELGYRO_LSM6DSM_H
#define __CROS_EC_ACCELGYRO_LSM6DSM_H

#include "stm_mems_common.h"
#include "mag_cal.h"
#include "mag_bmm150.h"
#include "mag_lis2mdl.h"

/*
 * 7-bit address is 110101xb. Where 'x' is determined
 * by the voltage on the ADDR pin
 */
#define LSM6DSM_ADDR0_FLAGS 0x6a
#define LSM6DSM_ADDR1_FLAGS 0x6b

/* COMMON DEFINE FOR ACCEL-GYRO SENSORS */
#define LSM6DSM_EN_BIT 0x01
#define LSM6DSM_DIS_BIT 0x00

/* Access to embedded sensor hub register bank */
#define LSM6DSM_FUNC_CFG_ACC_ADDR 0x01
#define LSM6DSM_FUNC_CFG_EN 0x80
#define LSM6DSM_FUNC_CFG_EN_B 0x20

/* FIFO decimator registers and bitmask */
#define LSM6DSM_FIFO_CTRL1_ADDR 0x06

/* Output data rate registers and masks */
#define LSM6DSM_ODR_REG(_sensor) (LSM6DSM_CTRL1_ADDR + _sensor)
#define LSM6DSM_ODR_MASK 0xf0

#define LSM6DSM_FIFO_CTRL2_ADDR 0x07

#define LSM6DSM_FIFO_CTRL3_ADDR 0x08
#define LSM6DSM_FIFO_DEC_XL_OFF 0
#define LSM6DSM_FIFO_DEC_G_OFF 3

#define LSM6DSM_FIFO_CTRL4_ADDR 0x09

#define LSM6DSM_FIFO_DECIMATOR(_dec) \
	(_dec < 8 ? _dec : (2 + __builtin_ctz(_dec)))

/* Hardware FIFO size in byte */
#define LSM6DSM_MAX_FIFO_SIZE 4096
#define LSM6DSM_MAX_FIFO_LENGTH (LSM6DSM_MAX_FIFO_SIZE / OUT_XYZ_SIZE)

#define LSM6DSM_FIFO_CTRL5_ADDR 0x0a
#define LSM6DSM_FIFO_CTRL5_ODR_OFF 3
#define LSM6DSM_FIFO_CTRL5_ODR_MASK (0xf << LSM6DSM_FIFO_CTRL5_ODR_OFF)
#define LSM6DSM_FIFO_CTRL5_MODE_MASK 0x07

#define LSM6DSM_INT1_CTRL 0x0d
#define LSM6DSM_INT_FIFO_TH 0x08
#define LSM6DSM_INT_FIFO_OVR 0x10
#define LSM6DSM_INT_FIFO_FULL 0x20
#define LSM6DSM_INT_SIGMO 0x40

/* Who Am I */
#define LSM6DSM_WHO_AM_I_REG 0x0f
/* LSM6DSM/LSM6DSL/LSM6DS3TR-C */
#define LSM6DSM_WHO_AM_I 0x6a
/* LSM6DS3 */
#define LSM6DS3_WHO_AM_I 0x69

#define LSM6DSM_CTRL1_ADDR 0x10
#define LSM6DSM_XL_ODR_MASK 0xf0

#define LSM6DSM_CTRL2_ADDR 0x11
#define LSM6DSM_CTRL3_ADDR 0x12
#define LSM6DSM_SW_RESET 0x01
#define LSM6DSM_IF_INC 0x04
#define LSM6DSM_PP_OD 0x10
#define LSM6DSM_H_L_ACTIVE 0x20
#define LSM6DSM_BDU 0x40
#define LSM6DSM_BOOT 0x80

#define LSM6DSM_CTRL4_ADDR 0x13
#define LSM6DSM_INT2_ON_INT1_MASK 0x20

#define LSM6DSM_CTRL6_ADDR 0x15
#define LSM6DSM_CTRL7_ADDR 0x16

#define LSM6DSM_CTRL10_ADDR 0x19
#define LSM6DSM_FUNC_EN_MASK 0x04
#define LSM6DSM_SIG_MOT_MASK 0x01
#define LSM6DSM_EMBED_FUNC_EN 0x04
#define LSM6DSM_SIG_MOT_EN 0x01

/* Controller mode configuration register */
#define LSM6DSM_CONTROLLER_CFG_ADDR 0x1a
#define LSM6DSM_PASSTROUGH_MASK 0x1f
#define LSM6DSM_EXT_TRIGGER_EN 0x10
#define LSM6DSM_PULLUP_EN 0x08
#define LSM6DSM_I2C_PASS_THRU_MODE 0x04
#define LSM6DSM_I2C_CONTROLLER_ON 0x01

#define LSM6DSM_TAP_SRC_ADDR 0x1c
#define LSM6DSM_STAP_DETECT 0x20
#define LSM6DSM_DTAP_DETECT 0x10

#define LSM6DSM_STATUS_REG 0x1e

#define LSM6DSM_OUT_TEMP_L_ADDR 0x20

#define LSM6DSM_GYRO_OUT_X_L_ADDR 0x22
#define LSM6DSM_ACCEL_OUT_X_L_ADDR 0x28

#define LSM6DSM_SENSORHUB1_REG 0x2e

#define LSM6DSM_FIFO_STS1_ADDR 0x3a
#define LSM6DSM_FIFO_STS2_ADDR 0x3b
#define LSM6DSM_FIFO_DIFF_MASK 0x0fff
#define LSM6DSM_FIFO_EMPTY 0x1000
#define LSM6DSM_FIFO_FULL 0x2000
#define LSM6DSM_FIFO_DATA_OVR 0x4000
#define LSM6DSM_FIFO_WATERMARK 0x8000
#define LSM6DSM_FIFO_NODECIM 0x01

/* Out data register */
#define LSM6DSM_FIFO_DATA_ADDR 0x3e

/* Registers value for supported FIFO mode */
#define LSM6DSM_FIFO_MODE_BYPASS_VAL 0x00
#define LSM6DSM_FIFO_MODE_CONTINUOUS_VAL 0x06

#define LSM6DSM_FUNC_SRC1_ADDR 0x53
#define LSM6DSM_SENSORHUB_END_OP 0x01
#define LSM6DSM_SIGN_MOTION_IA 0x40

#define LSM6DSM_LIR_ADDR 0x58
#define LSM6DSM_LIR_MASK 0x01
#define LSM6DSM_EN_INT 0x80
#define LSM6DSM_EN_TAP 0x0e
#define LSM6DSM_TAP_MASK 0x8e

#define LSM6DSM_TAP_THS_6D 0x59
#define LSM6DSM_D4D_EN_MASK 0x80
#define LSM6DSM_TAP_TH_MASK 0x1f

#define LSM6DSM_INT_DUR2_ADDR 0x5a
#define LSM6DSM_TAP_DUR_MASK 0xf0
#define LSM6DSM_TAP_QUIET_MASK 0x0c

#define LSM6DSM_WUP_THS_ADDR 0x5b
#define LSM6DSM_S_D_TAP_MASK 0x80
#define LSM6DSM_STAP_EN 0
#define LSM6DSM_DTAP_EN 1

#define LSM6DSM_MD1_CFG_ADDR 0x5e
#define LSM6DSM_INT1_STAP 0x40
#define LSM6DSM_INT1_DTAP 0x08

/* Register values for Sensor Hub Slave 0 / Bank A */
#define LSM6DSM_SLV0_ADD_ADDR 0x02
#define LSM6DSM_SLV0_ADDR_SHFT 1
#define LSM6DSM_SLV0_ADDR_MASK 0xfe
#define LSM6DSM_SLV0_RD_BIT 0x01

#define LSM6DSM_SLV0_SUBADD_ADDR 0x03

#define LSM6DSM_SLV0_CONFIG_ADDR 0x04
#define LSM6DSM_SLV0_SLV_RATE_SHFT 6
#define LSM6DSM_SLV0_SLV_RATE_MASK 0xc0
#define LSM6DSM_SLV0_AUX_SENS_SHFT 4
#define LSM6DSM_SLV0_AUX_SENS_MASK 0x30
#define LSM6DSM_SLV0_NUM_OPS_MASK 0x07

#define LSM6DSM_SLV1_CONFIG_ADDR 0x07
#define LSM6DSM_SLV0_WR_ONCE_MASK 0x20

#define LSM6DSM_DATA_WRITE_SUB_SLV0_ADDR 0x0e

/* Define device available in FIFO pattern */
enum dev_fifo {
	FIFO_DEV_INVALID = -1,
	FIFO_DEV_GYRO = 0,
	FIFO_DEV_ACCEL,
	FIFO_DEV_MAG,
};

#ifdef CONFIG_LSM6DSM_SEC_I2C
#define FIFO_DEV_NUM (FIFO_DEV_MAG + 1)
#else
#define FIFO_DEV_NUM (FIFO_DEV_ACCEL + 1)
#endif

struct fstatus {
	uint16_t len;
	uint16_t pattern;
};

/* Absolute maximum rate for acc and gyro sensors */
#define LSM6DSM_ODR_MIN_VAL 13000
#define LSM6DSM_ODR_MAX_VAL \
	MOTION_MAX_SENSOR_FREQUENCY(416000, LSM6DSM_ODR_MIN_VAL)

/* ODR reg value from selected data rate in mHz */
#define LSM6DSM_ODR_TO_REG(_odr) (__fls(_odr / LSM6DSM_ODR_MIN_VAL) + 1)

/* normalized ODR value from selected data rate in mHz */
#define LSM6DSM_REG_TO_ODR(_reg) (LSM6DSM_ODR_MIN_VAL << (_reg - 1))

/* Full Scale range value and gain for Acc */
#define LSM6DSM_FS_LIST_NUM 4

#define LSM6DSM_ACCEL_FS_ADDR 0x10
#define LSM6DSM_ACCEL_FS_MASK 0x0c

#define LSM6DSM_ACCEL_FS_2G_VAL 0x00
#define LSM6DSM_ACCEL_FS_4G_VAL 0x02
#define LSM6DSM_ACCEL_FS_8G_VAL 0x03
#define LSM6DSM_ACCEL_FS_16G_VAL 0x01

#define LSM6DSM_ACCEL_FS_MAX_VAL 16

/* Accel Reg value from Full Scale */
#define LSM6DSM_ACCEL_FS_REG(_fs)               \
	(_fs == 2  ? LSM6DSM_ACCEL_FS_2G_VAL :  \
	 _fs == 16 ? LSM6DSM_ACCEL_FS_16G_VAL : \
		     __fls(_fs))

/* Accel normalized FS value from Full Scale */
#define LSM6DSM_ACCEL_NORMALIZE_FS(_fs) (1 << __fls(_fs))

/* Full Scale range value and gain for Gyro */
#define LSM6DSM_GYRO_FS_ADDR 0x11
#define LSM6DSM_GYRO_FS_MASK 0x0c

/* Supported gyroscope ranges:
 * name(dps) | register | gain(udps/LSB) | actual value(dps)
 * 250       | 0        | 8750           |  286.72
 * 500       | 1        | 17500          |  573.44
 * 1000      | 2        | 35000          |  1146.88
 * 2000      | 3        | 70000          |  2293.76
 */
#define LSM6DSM_GYRO_FS_MIN_VAL_MDPS ((8750 << 15) / 1000)
#define LSM6DSM_GYRO_FS_MAX_REG_VAL 3

/* Gyro Reg value for Full Scale selection */
#define LSM6DSM_GYRO_FS_REG(_fs) \
	__fls(MAX(1, (_fs * 1000) / LSM6DSM_GYRO_FS_MIN_VAL_MDPS))

/* Gyro normalized FS value from Full Scale register */
#define LSM6DSM_GYRO_NORMALIZE_FS(_reg) \
	((LSM6DSM_GYRO_FS_MIN_VAL_MDPS << (_reg)) / 1000)

/* FS register address/mask for Acc/Gyro sensors */
#define LSM6DSM_RANGE_REG(_sensor) (LSM6DSM_ACCEL_FS_ADDR + (_sensor))
#define LSM6DSM_RANGE_MASK 0x0c

/* Status register bitmask for Acc/Gyro data ready */
enum lsm6dsm_status {
	LSM6DSM_STS_DOWN = 0x00,
	LSM6DSM_STS_XLDA_UP = 0x01,
	LSM6DSM_STS_GDA_UP = 0x02
};

#define LSM6DSM_STS_XLDA_MASK 0x01
#define LSM6DSM_STS_GDA_MASK 0x02

/* Sensor resolution in number of bits: fixed 16 bit */
#define LSM6DSM_RESOLUTION 16

extern const struct accelgyro_drv lsm6dsm_drv;

void lsm6dsm_interrupt(enum gpio_signal signal);

struct lsm6dsm_fifo_data {
	/*
	 * FIFO data order is based on the ODR of each sensors.
	 * For example Acc @ 52 Hz, Gyro @ 26 Hz Mag @ 13 Hz in FIFO we have
	 * for each pattern this data samples:
	 *  ________ _______ _______ _______ ________ _______ _______
	 * | Gyro_0 | Acc_0 | Mag_0 | Acc_1 | Gyro_1 | Acc_2 | Acc_3 |
	 * |________|_______|_______|_______|________|_______|_______|
	 *
	 * Total samples for each pattern: 2 Gyro, 4 Acc, 1 Mag
	 */
	/* Calculated samples in a pattern, based on ODR. */
	int samples_in_pattern[FIFO_DEV_NUM];

	/* Sum of all samples_in_pattern. */
	int total_samples_in_pattern;
};

/**
 * Structure used to hold fifo state. This struct should only be used if
 * CONFIG_ACCEL_FIFO is defined.
 */
struct lsm6dsm_accel_fifo_state {
	struct lsm6dsm_fifo_data config;
	struct lsm6dsm_fifo_data current;
	int next_in_pattern;
	/*
	 * After an ODR change, the sensor filters need settling time; discard
	 * initial samples with incorrect values
	 */
	unsigned int samples_to_discard[FIFO_DEV_NUM];
};

/*
 * lsm6dsm_data is used for accel gyro and the sensor connect to a LSM6DSM.
 *
 * +---- lsm6dsm_data ------------------------------------------------+
 * | +--- stprivate_data ---+                                         |
 * | |                      | ST common data for accelerometer        |
 * | +----------------------+                                         |
 * | +--- stprivate_data ---+                                         |
 * | |                      | ST common data for gyroscope            |
 * | +----------------------+                                         |
 * | +--- stprivate_data ---+                                         |
 * | |                      | ST common data for LIS2MDL magnetomer   |
 * | +----------------------+ (optional)                              |
 * |                                                                  |
 * | Fifo Information                                                 |
 * |                                                                  |
 * | +----- Magnetometer information -----------------------------+   |
 * | | +--- mag_cal_t ------+                                     |   |
 * | | |                    | Data for online calibration         |   |
 * | | +--------------------+                                     |   |
 * | | Other privata data                                         |   |
 * | +------------------------------------------------------------+   |
 * +------------------------------------------------------------------+
 *
 * In motion_sensors array, use LSM6DSM_ST_DATA to point drv_data
 * to the right st_data structure.
 */
struct lsm6dsm_data {
#ifdef CONFIG_MAG_LSM6DSM_LIS2MDL
	/* LIS2MDL uses st_mems_common and needs stprivate_data */
	struct stprivate_data st_data[3];
#else
	/* BMM150 doesn't use st_mems_common; no stprivate_data */
	struct stprivate_data st_data[2];
#endif
	struct lsm6dsm_accel_fifo_state *accel_fifo_state;
#if defined(CONFIG_LSM6DSM_SEC_I2C) && defined(CONFIG_MAG_CALIBRATE)
	union {
#ifdef CONFIG_MAG_LSM6DSM_BMM150
		struct bmm150_private_data compass;
#endif
#ifdef CONFIG_MAG_LSM6DSM_LIS2MDL
		struct lis2mdl_private_data compass;
#endif
		struct mag_cal_t cal;
	};
#endif /* CONFIG_MAG_CALIBRATE */
};

#ifdef CONFIG_ACCEL_FIFO
#define LSM6DSM_ACCEL_FIFO_STATE (&((struct lsm6dsm_accel_fifo_state){}))
#else
#define LSM6DSM_ACCEL_FIFO_STATE NULL
#endif

#define LSM6DSM_DATA                                          \
	((struct lsm6dsm_data){                               \
		.accel_fifo_state = LSM6DSM_ACCEL_FIFO_STATE, \
	})

/*
 * Note: The specific number of samples to discard depends on the filters
 * configured for the chip, as well as the ODR being set.  For most of our
 * allowed ODRs, 5 should suffice.
 * See: ST's LSM6DSM application notes (AN4987) Tables 17 and 19 for details
 */
#define LSM6DSM_DISCARD_SAMPLES 5

#define LSM6DSM_ST_DATA(g, type) (&(&(g))->st_data[(type)])

#define LSM6DSM_MAIN_SENSOR(_s) ((_s) - (_s)->type)

#define LSM6DSM_GET_DATA(_s) \
	((struct lsm6dsm_data *)(LSM6DSM_MAIN_SENSOR(_s))->drv_data)

#if defined(CONFIG_LSM6DSM_SEC_I2C) && defined(CONFIG_MAG_CALIBRATE)
#define LIS2MDL_CAL(_s) (&LSM6DSM_GET_DATA(_s)->cal)
#endif

int lsm6dsm_set_data_rate(const struct motion_sensor_t *s, int rate, int rnd);

#if defined(CONFIG_ZEPHYR)
/* Get the motion sensor ID of the LSM6DSM sensor that generates the
 * interrupt. The interrupt is converted to the event and transferred to
 * motion sense task that actually handles the interrupt.
 *
 * Here we use an alias (lsm6dsm_int) to get the motion sensor ID. This alias
 * MUST be defined for this driver to work.
 * aliases {
 *   lsm6dsm-int = &lid_accel;
 * };
 */
#if DT_NODE_EXISTS(DT_ALIAS(lsm6dsm_int))
#define CONFIG_ACCEL_LSM6DSM_INT_EVENT \
	TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(lsm6dsm_int)))
#endif
#endif

#endif /* __CROS_EC_ACCELGYRO_LSM6DSM_H */