/* Copyright 2019 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* LSM6DSO Accel and Gyro driver for Chrome EC */

#ifndef __CROS_EC_ACCELGYRO_LSM6DSO_H
#define __CROS_EC_ACCELGYRO_LSM6DSO_H

#include "stm_mems_common.h"

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

/* Access to embedded sensor hub register bank */
#define LSM6DSO_FUNC_CFG_ACC_ADDR	0x01
#define LSM6DSO_FUNC_CFG_EN			0x80

/* Who Am I */
#define LSM6DSO_WHO_AM_I_REG		0x0f
#define LSM6DSO_WHO_AM_I		0x6c

/* Common defines for Acc and Gyro sensors */
#define LSM6DSO_EN_BIT				0x01
#define LSM6DSO_DIS_BIT				0x00

#define LSM6DSO_GYRO_OUT_X_L_ADDR	0x22
#define LSM6DSO_ACCEL_OUT_X_L_ADDR	0x28

#define LSM6DSO_CTRL1_ADDR		0x10
#define LSM6DSO_CTRL2_ADDR		0x11
#define LSM6DSO_CTRL3_ADDR		0x12
#define LSM6DSO_SW_RESET			0x01
#define LSM6DSO_IF_INC				0x04
#define LSM6DSO_PP_OD				0x10
#define LSM6DSO_H_L_ACTIVE			0x20
#define LSM6DSO_BDU				0x40

#define LSM6DSO_CTRL4_ADDR		0x13
#define LSM6DSO_INT2_ON_INT1_MASK		0x20

#define LSM6DSO_CTRL5_ADDR		0x14
#define LSM6DSO_CTRL6_ADDR		0x15
#define LSM6DSO_CTRL7_ADDR		0x16
#define LSM6DSO_CTRL8_ADDR		0x17
#define LSM6DSO_CTRL9_ADDR		0x18

#define LSM6DSO_CTRL10_ADDR		0x19
#define LSM6DSO_TIMESTAMP_EN    		0x20

#define LSM6DSO_STATUS_REG		0x1e

/* Output data rate registers and masks */
#define LSM6DSO_ODR_REG(_sensor) \
	(LSM6DSO_CTRL1_ADDR + (_sensor))
#define LSM6DSO_ODR_MASK			0xf0

/* Hardware FIFO size in byte */
#define LSM6DSO_MAX_FIFO_SIZE		4096
#define LSM6DSO_MAX_FIFO_LENGTH	(LSM6DSO_MAX_FIFO_SIZE / OUT_XYZ_SIZE)

/* FIFO decimator registers and bitmask */
#define LSM6DSO_FIFO_CTRL1_ADDR		0x07
#define LSM6DSO_FIFO_CTRL2_ADDR		0x08

#define LSM6DSO_FIFO_CTRL3_ADDR		0x09
#define LSM6DSO_FIFO_ODR_XL_MASK		0x0f
#define LSM6DSO_FIFO_ODR_G_MASK			0xf0

#define LSM6DSO_FIFO_CTRL4_ADDR		0x0a
#define LSM6DSO_FIFO_MODE_MASK			0x07

#define LSM6DSO_INT1_CTRL		0x0d
#define LSM6DSO_INT2_CTRL		0x0e
#define LSM6DSO_INT_FIFO_TH			0x08
#define LSM6DSO_INT_FIFO_OVR			0x10
#define LSM6DSO_INT_FIFO_FULL			0x20

#define LSM6DSO_FIFO_STS1_ADDR		0x3a
#define LSM6DSO_FIFO_STS2_ADDR		0x3b
#define LSM6DSO_FIFO_DIFF_MASK			0x07ff
#define LSM6DSO_FIFO_FULL			0x2000
#define LSM6DSO_FIFO_DATA_OVR			0x4000
#define LSM6DSO_FIFO_WATERMARK			0x8000

/* Out FIFO data register */
#define LSM6DSO_FIFO_DATA_ADDR_TAG	0x78

/* Registers value for supported FIFO mode */
#define LSM6DSO_FIFO_MODE_BYPASS_VAL	0x00
#define LSM6DSO_FIFO_MODE_CONTINUOUS_VAL	0x06

/* Define device available in FIFO pattern */
enum lsm6dso_dev_fifo {
	LSM6DSO_FIFO_DEV_INVALID = -1,
	LSM6DSO_FIFO_DEV_GYRO = 0,
	LSM6DSO_FIFO_DEV_ACCEL,
	LSM6DSO_FIFO_DEV_NUM,
};

/* Define FIFO data pattern, tag and len */
#define LSM6DSO_SAMPLE_SIZE		6
#define LSM6DSO_TS_SAMPLE_SIZE		4
#define LSM6DSO_TAG_SIZE		1
#define LSM6DSO_FIFO_SAMPLE_SIZE	LSM6DSO_SAMPLE_SIZE + LSM6DSO_TAG_SIZE
#define LSM6DSO_MAX_FIFO_DEPTH		416

enum lsm6dso_tag_fifo {
	LSM6DSO_GYRO_TAG = 0x01,
	LSM6DSO_ACC_TAG = 0x02,
};

struct lsm6dso_fstatus {
	uint16_t len;
	uint16_t pattern;
};

/* Absolute maximum rate for Acc and Gyro sensors */
#define LSM6DSO_ODR_MIN_VAL		13000
#define LSM6DSO_ODR_MAX_VAL \
	MOTION_MAX_SENSOR_FREQUENCY(416000, 13000)

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

#define LSM6DSO_FIFO_ODR_TO_REG(_s) \
	(_s->type == MOTIONSENSE_TYPE_ACCEL ? LSM6DSO_FIFO_ODR_XL_MASK : \
	 LSM6DSO_FIFO_ODR_G_MASK)

/* Normalized ODR values from selected data rate in mHz */
#define LSM6DSO_REG_TO_ODR(_reg) (LSM6DSO_ODR_MIN_VAL << (_reg - 1))

/* Full Scale ranges value and gain for Acc */
#define LSM6DSO_FS_LIST_NUM		4

#define LSM6DSO_ACCEL_FS_ADDR		0x10
#define LSM6DSO_ACCEL_FS_MASK			0x0c

#define LSM6DSO_ACCEL_FS_2G_VAL		0x00
#define LSM6DSO_ACCEL_FS_4G_VAL		0x02
#define LSM6DSO_ACCEL_FS_8G_VAL		0x03
#define LSM6DSO_ACCEL_FS_16G_VAL	0x01

#define LSM6DSO_ACCEL_FS_MAX_VAL	16

/* Accel reg value from Full Scale range */
static inline uint8_t lsm6dso_accel_fs_reg(int fs)
{
	uint8_t ret;

	switch(fs) {
	case 2:
		ret = LSM6DSO_ACCEL_FS_2G_VAL;
		break;
	case 16:
		ret = LSM6DSO_ACCEL_FS_16G_VAL;
		break;
	default:
		ret = __fls(fs);
		break;
	}

	return ret;
}

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

/* Full Scale range value and gain for Gyro */
#define LSM6DSO_GYRO_FS_ADDR		0x11
#define LSM6DSO_GYRO_FS_MASK			0x0c

/* Minimal Gyro range in mDPS */
#define LSM6DSO_GYRO_FS_MIN_VAL_MDPS ((8750 << 15) / 1000)
#define LSM6DSO_GYRO_FS_MAX_REG_VAL 3

/* Gyro reg value for Full Scale selection in DPS */
#define LSM6DSO_GYRO_FS_REG(_fs) \
	__fls(MAX(1, (_fs * 1000) / LSM6DSO_GYRO_FS_MIN_VAL_MDPS))

/* Gyro normalized FS value (in DPS) from Full Scale register */
#define LSM6DSO_GYRO_NORMALIZE_FS(_reg) \
	((LSM6DSO_GYRO_FS_MIN_VAL_MDPS << (_reg)) / 1000)

/* FS register address/mask for Acc/Gyro sensors */
#define LSM6DSO_RANGE_REG(_sensor)  	(LSM6DSO_ACCEL_FS_ADDR + (_sensor))
#define LSM6DSO_RANGE_MASK  			0x0c

/* Status register bit for Acc/Gyro data ready */
enum lsm6dso_status {
	LSM6DSO_STS_DOWN = 0x00,
	LSM6DSO_STS_XLDA_UP = 0x01,
	LSM6DSO_STS_GDA_UP = 0x02
};

/* Status register bitmask for Acc/Gyro data ready */
#define LSM6DSO_STS_XLDA_MASK			0x01
#define LSM6DSO_STS_GDA_MASK			0x02

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

/* Aggregate private data for all supported sensor (Acc, Gyro) */
struct lsm6dso_data {
	struct stprivate_data st_data[LSM6DSO_FIFO_DEV_NUM];
};

/*
 * 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, 3 should suffice.
 * See: ST's LSM6DSO application notes (AN5192) Tables 12 and 18 for details
 */
#define LSM6DSO_DISCARD_SAMPLES 3

#define LSM6DSO_GET_DATA(_s) ((struct stprivate_data *)((_s)->drv_data))

/* Macro to initialize motion_sensors structure */
#define LSM6DSO_ST_DATA(g, type) (&(&(g))->st_data[(type)])
#define LSM6DSO_MAIN_SENSOR(_s) ((_s) - (_s)->type)

extern const struct accelgyro_drv lsm6dso_drv;

void lsm6dso_interrupt(enum gpio_signal signal);

#endif /* __CROS_EC_ACCELGYRO_LSM6DSO_H */
