xref: /linux/drivers/iio/imu/bmi160/bmi160_core.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
137402329SMartin Kelly // SPDX-License-Identifier: GPL-2.0
277c4ad2dSDaniel Baluta /*
377c4ad2dSDaniel Baluta  * BMI160 - Bosch IMU (accel, gyro plus external magnetometer)
477c4ad2dSDaniel Baluta  *
577c4ad2dSDaniel Baluta  * Copyright (c) 2016, Intel Corporation.
6895bf81eSMartin Kelly  * Copyright (c) 2019, Martin Kelly.
777c4ad2dSDaniel Baluta  *
877c4ad2dSDaniel Baluta  * IIO core driver for BMI160, with support for I2C/SPI busses
977c4ad2dSDaniel Baluta  *
10895bf81eSMartin Kelly  * TODO: magnetometer, hardware FIFO
1177c4ad2dSDaniel Baluta  */
1277c4ad2dSDaniel Baluta #include <linux/module.h>
1377c4ad2dSDaniel Baluta #include <linux/regmap.h>
1477c4ad2dSDaniel Baluta #include <linux/delay.h>
15895bf81eSMartin Kelly #include <linux/irq.h>
165f474919SAndy Shevchenko #include <linux/property.h>
175dea3fb0SJonathan Albrieux #include <linux/regulator/consumer.h>
1877c4ad2dSDaniel Baluta 
1977c4ad2dSDaniel Baluta #include <linux/iio/iio.h>
2077c4ad2dSDaniel Baluta #include <linux/iio/triggered_buffer.h>
2177c4ad2dSDaniel Baluta #include <linux/iio/trigger_consumer.h>
2277c4ad2dSDaniel Baluta #include <linux/iio/buffer.h>
23216912e3SDaniel Baluta #include <linux/iio/sysfs.h>
24895bf81eSMartin Kelly #include <linux/iio/trigger.h>
2577c4ad2dSDaniel Baluta 
2677c4ad2dSDaniel Baluta #include "bmi160.h"
2777c4ad2dSDaniel Baluta 
2877c4ad2dSDaniel Baluta #define BMI160_REG_CHIP_ID	0x00
29cedb9bd8SDanila Tikhonov #define BMI120_CHIP_ID_VAL	0xD3
3077c4ad2dSDaniel Baluta #define BMI160_CHIP_ID_VAL	0xD1
3177c4ad2dSDaniel Baluta 
3277c4ad2dSDaniel Baluta #define BMI160_REG_PMU_STATUS	0x03
3377c4ad2dSDaniel Baluta 
3477c4ad2dSDaniel Baluta /* X axis data low byte address, the rest can be obtained using axis offset */
3577c4ad2dSDaniel Baluta #define BMI160_REG_DATA_MAGN_XOUT_L	0x04
3677c4ad2dSDaniel Baluta #define BMI160_REG_DATA_GYRO_XOUT_L	0x0C
3777c4ad2dSDaniel Baluta #define BMI160_REG_DATA_ACCEL_XOUT_L	0x12
3877c4ad2dSDaniel Baluta 
3977c4ad2dSDaniel Baluta #define BMI160_REG_ACCEL_CONFIG		0x40
4077c4ad2dSDaniel Baluta #define BMI160_ACCEL_CONFIG_ODR_MASK	GENMASK(3, 0)
4177c4ad2dSDaniel Baluta #define BMI160_ACCEL_CONFIG_BWP_MASK	GENMASK(6, 4)
4277c4ad2dSDaniel Baluta 
4377c4ad2dSDaniel Baluta #define BMI160_REG_ACCEL_RANGE		0x41
4477c4ad2dSDaniel Baluta #define BMI160_ACCEL_RANGE_2G		0x03
4577c4ad2dSDaniel Baluta #define BMI160_ACCEL_RANGE_4G		0x05
4677c4ad2dSDaniel Baluta #define BMI160_ACCEL_RANGE_8G		0x08
4777c4ad2dSDaniel Baluta #define BMI160_ACCEL_RANGE_16G		0x0C
4877c4ad2dSDaniel Baluta 
4977c4ad2dSDaniel Baluta #define BMI160_REG_GYRO_CONFIG		0x42
5077c4ad2dSDaniel Baluta #define BMI160_GYRO_CONFIG_ODR_MASK	GENMASK(3, 0)
5177c4ad2dSDaniel Baluta #define BMI160_GYRO_CONFIG_BWP_MASK	GENMASK(5, 4)
5277c4ad2dSDaniel Baluta 
5377c4ad2dSDaniel Baluta #define BMI160_REG_GYRO_RANGE		0x43
5477c4ad2dSDaniel Baluta #define BMI160_GYRO_RANGE_2000DPS	0x00
5577c4ad2dSDaniel Baluta #define BMI160_GYRO_RANGE_1000DPS	0x01
5677c4ad2dSDaniel Baluta #define BMI160_GYRO_RANGE_500DPS	0x02
5777c4ad2dSDaniel Baluta #define BMI160_GYRO_RANGE_250DPS	0x03
5877c4ad2dSDaniel Baluta #define BMI160_GYRO_RANGE_125DPS	0x04
5977c4ad2dSDaniel Baluta 
6077c4ad2dSDaniel Baluta #define BMI160_REG_CMD			0x7E
6177c4ad2dSDaniel Baluta #define BMI160_CMD_ACCEL_PM_SUSPEND	0x10
6277c4ad2dSDaniel Baluta #define BMI160_CMD_ACCEL_PM_NORMAL	0x11
6377c4ad2dSDaniel Baluta #define BMI160_CMD_ACCEL_PM_LOW_POWER	0x12
6477c4ad2dSDaniel Baluta #define BMI160_CMD_GYRO_PM_SUSPEND	0x14
6577c4ad2dSDaniel Baluta #define BMI160_CMD_GYRO_PM_NORMAL	0x15
6677c4ad2dSDaniel Baluta #define BMI160_CMD_GYRO_PM_FAST_STARTUP	0x17
6777c4ad2dSDaniel Baluta #define BMI160_CMD_SOFTRESET		0xB6
6877c4ad2dSDaniel Baluta 
69895bf81eSMartin Kelly #define BMI160_REG_INT_EN		0x51
70895bf81eSMartin Kelly #define BMI160_DRDY_INT_EN		BIT(4)
71895bf81eSMartin Kelly 
72895bf81eSMartin Kelly #define BMI160_REG_INT_OUT_CTRL		0x53
73895bf81eSMartin Kelly #define BMI160_INT_OUT_CTRL_MASK	0x0f
74895bf81eSMartin Kelly #define BMI160_INT1_OUT_CTRL_SHIFT	0
75895bf81eSMartin Kelly #define BMI160_INT2_OUT_CTRL_SHIFT	4
76895bf81eSMartin Kelly #define BMI160_EDGE_TRIGGERED		BIT(0)
77895bf81eSMartin Kelly #define BMI160_ACTIVE_HIGH		BIT(1)
78895bf81eSMartin Kelly #define BMI160_OPEN_DRAIN		BIT(2)
79895bf81eSMartin Kelly #define BMI160_OUTPUT_EN		BIT(3)
80895bf81eSMartin Kelly 
81895bf81eSMartin Kelly #define BMI160_REG_INT_LATCH		0x54
82895bf81eSMartin Kelly #define BMI160_INT1_LATCH_MASK		BIT(4)
83895bf81eSMartin Kelly #define BMI160_INT2_LATCH_MASK		BIT(5)
84895bf81eSMartin Kelly 
85895bf81eSMartin Kelly /* INT1 and INT2 are in the opposite order as in INT_OUT_CTRL! */
86895bf81eSMartin Kelly #define BMI160_REG_INT_MAP		0x56
87895bf81eSMartin Kelly #define BMI160_INT1_MAP_DRDY_EN		0x80
88895bf81eSMartin Kelly #define BMI160_INT2_MAP_DRDY_EN		0x08
89895bf81eSMartin Kelly 
9077c4ad2dSDaniel Baluta #define BMI160_REG_DUMMY		0x7F
9177c4ad2dSDaniel Baluta 
92895bf81eSMartin Kelly #define BMI160_NORMAL_WRITE_USLEEP	2
93895bf81eSMartin Kelly #define BMI160_SUSPENDED_WRITE_USLEEP	450
94895bf81eSMartin Kelly 
9501d1f7a9SMarcin Niestroj #define BMI160_ACCEL_PMU_MIN_USLEEP	3800
9601d1f7a9SMarcin Niestroj #define BMI160_GYRO_PMU_MIN_USLEEP	80000
9777c4ad2dSDaniel Baluta #define BMI160_SOFTRESET_USLEEP		1000
9877c4ad2dSDaniel Baluta 
9977c4ad2dSDaniel Baluta #define BMI160_CHANNEL(_type, _axis, _index) {			\
10077c4ad2dSDaniel Baluta 	.type = _type,						\
10177c4ad2dSDaniel Baluta 	.modified = 1,						\
10277c4ad2dSDaniel Baluta 	.channel2 = IIO_MOD_##_axis,				\
10377c4ad2dSDaniel Baluta 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
10477c4ad2dSDaniel Baluta 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |  \
10577c4ad2dSDaniel Baluta 		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
10677c4ad2dSDaniel Baluta 	.scan_index = _index,					\
10777c4ad2dSDaniel Baluta 	.scan_type = {						\
10877c4ad2dSDaniel Baluta 		.sign = 's',					\
10977c4ad2dSDaniel Baluta 		.realbits = 16,					\
11077c4ad2dSDaniel Baluta 		.storagebits = 16,				\
11177c4ad2dSDaniel Baluta 		.endianness = IIO_LE,				\
11277c4ad2dSDaniel Baluta 	},							\
113812a46b7SJonathan Albrieux 	.ext_info = bmi160_ext_info,				\
11477c4ad2dSDaniel Baluta }
11577c4ad2dSDaniel Baluta 
116cedb9bd8SDanila Tikhonov static const u8 bmi_chip_ids[] = {
117cedb9bd8SDanila Tikhonov 	BMI120_CHIP_ID_VAL,
118cedb9bd8SDanila Tikhonov 	BMI160_CHIP_ID_VAL,
119cedb9bd8SDanila Tikhonov };
120cedb9bd8SDanila Tikhonov 
12177c4ad2dSDaniel Baluta /* scan indexes follow DATA register order */
12277c4ad2dSDaniel Baluta enum bmi160_scan_axis {
12377c4ad2dSDaniel Baluta 	BMI160_SCAN_EXT_MAGN_X = 0,
12477c4ad2dSDaniel Baluta 	BMI160_SCAN_EXT_MAGN_Y,
12577c4ad2dSDaniel Baluta 	BMI160_SCAN_EXT_MAGN_Z,
12677c4ad2dSDaniel Baluta 	BMI160_SCAN_RHALL,
12777c4ad2dSDaniel Baluta 	BMI160_SCAN_GYRO_X,
12877c4ad2dSDaniel Baluta 	BMI160_SCAN_GYRO_Y,
12977c4ad2dSDaniel Baluta 	BMI160_SCAN_GYRO_Z,
13077c4ad2dSDaniel Baluta 	BMI160_SCAN_ACCEL_X,
13177c4ad2dSDaniel Baluta 	BMI160_SCAN_ACCEL_Y,
13277c4ad2dSDaniel Baluta 	BMI160_SCAN_ACCEL_Z,
13377c4ad2dSDaniel Baluta 	BMI160_SCAN_TIMESTAMP,
13477c4ad2dSDaniel Baluta };
13577c4ad2dSDaniel Baluta 
13677c4ad2dSDaniel Baluta enum bmi160_sensor_type {
13777c4ad2dSDaniel Baluta 	BMI160_ACCEL	= 0,
13877c4ad2dSDaniel Baluta 	BMI160_GYRO,
13977c4ad2dSDaniel Baluta 	BMI160_EXT_MAGN,
14077c4ad2dSDaniel Baluta 	BMI160_NUM_SENSORS /* must be last */
14177c4ad2dSDaniel Baluta };
14277c4ad2dSDaniel Baluta 
143895bf81eSMartin Kelly enum bmi160_int_pin {
144895bf81eSMartin Kelly 	BMI160_PIN_INT1,
145895bf81eSMartin Kelly 	BMI160_PIN_INT2
14677c4ad2dSDaniel Baluta };
14777c4ad2dSDaniel Baluta 
14877c4ad2dSDaniel Baluta const struct regmap_config bmi160_regmap_config = {
14977c4ad2dSDaniel Baluta 	.reg_bits = 8,
15077c4ad2dSDaniel Baluta 	.val_bits = 8,
15177c4ad2dSDaniel Baluta };
1522a8efd8bSJonathan Cameron EXPORT_SYMBOL_NS(bmi160_regmap_config, IIO_BMI160);
15377c4ad2dSDaniel Baluta 
15477c4ad2dSDaniel Baluta struct bmi160_regs {
15577c4ad2dSDaniel Baluta 	u8 data; /* LSB byte register for X-axis */
15677c4ad2dSDaniel Baluta 	u8 config;
15777c4ad2dSDaniel Baluta 	u8 config_odr_mask;
15877c4ad2dSDaniel Baluta 	u8 config_bwp_mask;
15977c4ad2dSDaniel Baluta 	u8 range;
16077c4ad2dSDaniel Baluta 	u8 pmu_cmd_normal;
16177c4ad2dSDaniel Baluta 	u8 pmu_cmd_suspend;
16277c4ad2dSDaniel Baluta };
16377c4ad2dSDaniel Baluta 
16477c4ad2dSDaniel Baluta static struct bmi160_regs bmi160_regs[] = {
16577c4ad2dSDaniel Baluta 	[BMI160_ACCEL] = {
16677c4ad2dSDaniel Baluta 		.data	= BMI160_REG_DATA_ACCEL_XOUT_L,
16777c4ad2dSDaniel Baluta 		.config	= BMI160_REG_ACCEL_CONFIG,
16877c4ad2dSDaniel Baluta 		.config_odr_mask = BMI160_ACCEL_CONFIG_ODR_MASK,
16977c4ad2dSDaniel Baluta 		.config_bwp_mask = BMI160_ACCEL_CONFIG_BWP_MASK,
17077c4ad2dSDaniel Baluta 		.range	= BMI160_REG_ACCEL_RANGE,
17177c4ad2dSDaniel Baluta 		.pmu_cmd_normal = BMI160_CMD_ACCEL_PM_NORMAL,
17277c4ad2dSDaniel Baluta 		.pmu_cmd_suspend = BMI160_CMD_ACCEL_PM_SUSPEND,
17377c4ad2dSDaniel Baluta 	},
17477c4ad2dSDaniel Baluta 	[BMI160_GYRO] = {
17577c4ad2dSDaniel Baluta 		.data	= BMI160_REG_DATA_GYRO_XOUT_L,
17677c4ad2dSDaniel Baluta 		.config	= BMI160_REG_GYRO_CONFIG,
17777c4ad2dSDaniel Baluta 		.config_odr_mask = BMI160_GYRO_CONFIG_ODR_MASK,
17877c4ad2dSDaniel Baluta 		.config_bwp_mask = BMI160_GYRO_CONFIG_BWP_MASK,
17977c4ad2dSDaniel Baluta 		.range	= BMI160_REG_GYRO_RANGE,
18077c4ad2dSDaniel Baluta 		.pmu_cmd_normal = BMI160_CMD_GYRO_PM_NORMAL,
18177c4ad2dSDaniel Baluta 		.pmu_cmd_suspend = BMI160_CMD_GYRO_PM_SUSPEND,
18277c4ad2dSDaniel Baluta 	},
18377c4ad2dSDaniel Baluta };
18477c4ad2dSDaniel Baluta 
18501d1f7a9SMarcin Niestroj static unsigned long bmi160_pmu_time[] = {
18601d1f7a9SMarcin Niestroj 	[BMI160_ACCEL] = BMI160_ACCEL_PMU_MIN_USLEEP,
18701d1f7a9SMarcin Niestroj 	[BMI160_GYRO] = BMI160_GYRO_PMU_MIN_USLEEP,
18877c4ad2dSDaniel Baluta };
18977c4ad2dSDaniel Baluta 
19077c4ad2dSDaniel Baluta struct bmi160_scale {
19177c4ad2dSDaniel Baluta 	u8 bits;
19277c4ad2dSDaniel Baluta 	int uscale;
19377c4ad2dSDaniel Baluta };
19477c4ad2dSDaniel Baluta 
19577c4ad2dSDaniel Baluta struct bmi160_odr {
19677c4ad2dSDaniel Baluta 	u8 bits;
19777c4ad2dSDaniel Baluta 	int odr;
19877c4ad2dSDaniel Baluta 	int uodr;
19977c4ad2dSDaniel Baluta };
20077c4ad2dSDaniel Baluta 
20177c4ad2dSDaniel Baluta static const struct bmi160_scale bmi160_accel_scale[] = {
20277c4ad2dSDaniel Baluta 	{ BMI160_ACCEL_RANGE_2G, 598},
20377c4ad2dSDaniel Baluta 	{ BMI160_ACCEL_RANGE_4G, 1197},
20477c4ad2dSDaniel Baluta 	{ BMI160_ACCEL_RANGE_8G, 2394},
20577c4ad2dSDaniel Baluta 	{ BMI160_ACCEL_RANGE_16G, 4788},
20677c4ad2dSDaniel Baluta };
20777c4ad2dSDaniel Baluta 
20877c4ad2dSDaniel Baluta static const struct bmi160_scale bmi160_gyro_scale[] = {
20977c4ad2dSDaniel Baluta 	{ BMI160_GYRO_RANGE_2000DPS, 1065},
21077c4ad2dSDaniel Baluta 	{ BMI160_GYRO_RANGE_1000DPS, 532},
21177c4ad2dSDaniel Baluta 	{ BMI160_GYRO_RANGE_500DPS, 266},
21277c4ad2dSDaniel Baluta 	{ BMI160_GYRO_RANGE_250DPS, 133},
21377c4ad2dSDaniel Baluta 	{ BMI160_GYRO_RANGE_125DPS, 66},
21477c4ad2dSDaniel Baluta };
21577c4ad2dSDaniel Baluta 
21677c4ad2dSDaniel Baluta struct bmi160_scale_item {
21777c4ad2dSDaniel Baluta 	const struct bmi160_scale *tbl;
21877c4ad2dSDaniel Baluta 	int num;
21977c4ad2dSDaniel Baluta };
22077c4ad2dSDaniel Baluta 
22177c4ad2dSDaniel Baluta static const struct  bmi160_scale_item bmi160_scale_table[] = {
22277c4ad2dSDaniel Baluta 	[BMI160_ACCEL] = {
22377c4ad2dSDaniel Baluta 		.tbl	= bmi160_accel_scale,
22477c4ad2dSDaniel Baluta 		.num	= ARRAY_SIZE(bmi160_accel_scale),
22577c4ad2dSDaniel Baluta 	},
22677c4ad2dSDaniel Baluta 	[BMI160_GYRO] = {
22777c4ad2dSDaniel Baluta 		.tbl	= bmi160_gyro_scale,
22877c4ad2dSDaniel Baluta 		.num	= ARRAY_SIZE(bmi160_gyro_scale),
22977c4ad2dSDaniel Baluta 	},
23077c4ad2dSDaniel Baluta };
23177c4ad2dSDaniel Baluta 
23277c4ad2dSDaniel Baluta static const struct bmi160_odr bmi160_accel_odr[] = {
2335ec97ba0SDaniel Baluta 	{0x01, 0, 781250},
2345ec97ba0SDaniel Baluta 	{0x02, 1, 562500},
2355ec97ba0SDaniel Baluta 	{0x03, 3, 125000},
2365ec97ba0SDaniel Baluta 	{0x04, 6, 250000},
2375ec97ba0SDaniel Baluta 	{0x05, 12, 500000},
23877c4ad2dSDaniel Baluta 	{0x06, 25, 0},
23977c4ad2dSDaniel Baluta 	{0x07, 50, 0},
24077c4ad2dSDaniel Baluta 	{0x08, 100, 0},
24177c4ad2dSDaniel Baluta 	{0x09, 200, 0},
24277c4ad2dSDaniel Baluta 	{0x0A, 400, 0},
24377c4ad2dSDaniel Baluta 	{0x0B, 800, 0},
24477c4ad2dSDaniel Baluta 	{0x0C, 1600, 0},
24577c4ad2dSDaniel Baluta };
24677c4ad2dSDaniel Baluta 
24777c4ad2dSDaniel Baluta static const struct bmi160_odr bmi160_gyro_odr[] = {
24877c4ad2dSDaniel Baluta 	{0x06, 25, 0},
24977c4ad2dSDaniel Baluta 	{0x07, 50, 0},
25077c4ad2dSDaniel Baluta 	{0x08, 100, 0},
25177c4ad2dSDaniel Baluta 	{0x09, 200, 0},
25277c4ad2dSDaniel Baluta 	{0x0A, 400, 0},
2535ec97ba0SDaniel Baluta 	{0x0B, 800, 0},
25477c4ad2dSDaniel Baluta 	{0x0C, 1600, 0},
25577c4ad2dSDaniel Baluta 	{0x0D, 3200, 0},
25677c4ad2dSDaniel Baluta };
25777c4ad2dSDaniel Baluta 
25877c4ad2dSDaniel Baluta struct bmi160_odr_item {
25977c4ad2dSDaniel Baluta 	const struct bmi160_odr *tbl;
26077c4ad2dSDaniel Baluta 	int num;
26177c4ad2dSDaniel Baluta };
26277c4ad2dSDaniel Baluta 
26377c4ad2dSDaniel Baluta static const struct  bmi160_odr_item bmi160_odr_table[] = {
26477c4ad2dSDaniel Baluta 	[BMI160_ACCEL] = {
26577c4ad2dSDaniel Baluta 		.tbl	= bmi160_accel_odr,
26677c4ad2dSDaniel Baluta 		.num	= ARRAY_SIZE(bmi160_accel_odr),
26777c4ad2dSDaniel Baluta 	},
26877c4ad2dSDaniel Baluta 	[BMI160_GYRO] = {
26977c4ad2dSDaniel Baluta 		.tbl	= bmi160_gyro_odr,
27077c4ad2dSDaniel Baluta 		.num	= ARRAY_SIZE(bmi160_gyro_odr),
27177c4ad2dSDaniel Baluta 	},
27277c4ad2dSDaniel Baluta };
27377c4ad2dSDaniel Baluta 
274812a46b7SJonathan Albrieux static const struct iio_mount_matrix *
bmi160_get_mount_matrix(const struct iio_dev * indio_dev,const struct iio_chan_spec * chan)275812a46b7SJonathan Albrieux bmi160_get_mount_matrix(const struct iio_dev *indio_dev,
276812a46b7SJonathan Albrieux 			const struct iio_chan_spec *chan)
277812a46b7SJonathan Albrieux {
278812a46b7SJonathan Albrieux 	struct bmi160_data *data = iio_priv(indio_dev);
279812a46b7SJonathan Albrieux 
280812a46b7SJonathan Albrieux 	return &data->orientation;
281812a46b7SJonathan Albrieux }
282812a46b7SJonathan Albrieux 
283812a46b7SJonathan Albrieux static const struct iio_chan_spec_ext_info bmi160_ext_info[] = {
284812a46b7SJonathan Albrieux 	IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmi160_get_mount_matrix),
285812a46b7SJonathan Albrieux 	{ }
286812a46b7SJonathan Albrieux };
287812a46b7SJonathan Albrieux 
28877c4ad2dSDaniel Baluta static const struct iio_chan_spec bmi160_channels[] = {
28977c4ad2dSDaniel Baluta 	BMI160_CHANNEL(IIO_ACCEL, X, BMI160_SCAN_ACCEL_X),
29077c4ad2dSDaniel Baluta 	BMI160_CHANNEL(IIO_ACCEL, Y, BMI160_SCAN_ACCEL_Y),
29177c4ad2dSDaniel Baluta 	BMI160_CHANNEL(IIO_ACCEL, Z, BMI160_SCAN_ACCEL_Z),
29277c4ad2dSDaniel Baluta 	BMI160_CHANNEL(IIO_ANGL_VEL, X, BMI160_SCAN_GYRO_X),
29377c4ad2dSDaniel Baluta 	BMI160_CHANNEL(IIO_ANGL_VEL, Y, BMI160_SCAN_GYRO_Y),
29477c4ad2dSDaniel Baluta 	BMI160_CHANNEL(IIO_ANGL_VEL, Z, BMI160_SCAN_GYRO_Z),
29577c4ad2dSDaniel Baluta 	IIO_CHAN_SOFT_TIMESTAMP(BMI160_SCAN_TIMESTAMP),
29677c4ad2dSDaniel Baluta };
29777c4ad2dSDaniel Baluta 
bmi160_to_sensor(enum iio_chan_type iio_type)29877c4ad2dSDaniel Baluta static enum bmi160_sensor_type bmi160_to_sensor(enum iio_chan_type iio_type)
29977c4ad2dSDaniel Baluta {
30077c4ad2dSDaniel Baluta 	switch (iio_type) {
30177c4ad2dSDaniel Baluta 	case IIO_ACCEL:
30277c4ad2dSDaniel Baluta 		return BMI160_ACCEL;
30377c4ad2dSDaniel Baluta 	case IIO_ANGL_VEL:
30477c4ad2dSDaniel Baluta 		return BMI160_GYRO;
30577c4ad2dSDaniel Baluta 	default:
30677c4ad2dSDaniel Baluta 		return -EINVAL;
30777c4ad2dSDaniel Baluta 	}
30877c4ad2dSDaniel Baluta }
30977c4ad2dSDaniel Baluta 
31077c4ad2dSDaniel Baluta static
bmi160_set_mode(struct bmi160_data * data,enum bmi160_sensor_type t,bool mode)31177c4ad2dSDaniel Baluta int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t,
31277c4ad2dSDaniel Baluta 		    bool mode)
31377c4ad2dSDaniel Baluta {
31477c4ad2dSDaniel Baluta 	int ret;
31577c4ad2dSDaniel Baluta 	u8 cmd;
31677c4ad2dSDaniel Baluta 
31777c4ad2dSDaniel Baluta 	if (mode)
31877c4ad2dSDaniel Baluta 		cmd = bmi160_regs[t].pmu_cmd_normal;
31977c4ad2dSDaniel Baluta 	else
32077c4ad2dSDaniel Baluta 		cmd = bmi160_regs[t].pmu_cmd_suspend;
32177c4ad2dSDaniel Baluta 
32277c4ad2dSDaniel Baluta 	ret = regmap_write(data->regmap, BMI160_REG_CMD, cmd);
32394edaac7SMartin Kelly 	if (ret)
32477c4ad2dSDaniel Baluta 		return ret;
32577c4ad2dSDaniel Baluta 
32601d1f7a9SMarcin Niestroj 	usleep_range(bmi160_pmu_time[t], bmi160_pmu_time[t] + 1000);
32777c4ad2dSDaniel Baluta 
32877c4ad2dSDaniel Baluta 	return 0;
32977c4ad2dSDaniel Baluta }
33077c4ad2dSDaniel Baluta 
33177c4ad2dSDaniel Baluta static
bmi160_set_scale(struct bmi160_data * data,enum bmi160_sensor_type t,int uscale)33277c4ad2dSDaniel Baluta int bmi160_set_scale(struct bmi160_data *data, enum bmi160_sensor_type t,
33377c4ad2dSDaniel Baluta 		     int uscale)
33477c4ad2dSDaniel Baluta {
33577c4ad2dSDaniel Baluta 	int i;
33677c4ad2dSDaniel Baluta 
33777c4ad2dSDaniel Baluta 	for (i = 0; i < bmi160_scale_table[t].num; i++)
33877c4ad2dSDaniel Baluta 		if (bmi160_scale_table[t].tbl[i].uscale == uscale)
33977c4ad2dSDaniel Baluta 			break;
34077c4ad2dSDaniel Baluta 
34177c4ad2dSDaniel Baluta 	if (i == bmi160_scale_table[t].num)
34277c4ad2dSDaniel Baluta 		return -EINVAL;
34377c4ad2dSDaniel Baluta 
34477c4ad2dSDaniel Baluta 	return regmap_write(data->regmap, bmi160_regs[t].range,
34577c4ad2dSDaniel Baluta 			    bmi160_scale_table[t].tbl[i].bits);
34677c4ad2dSDaniel Baluta }
34777c4ad2dSDaniel Baluta 
34877c4ad2dSDaniel Baluta static
bmi160_get_scale(struct bmi160_data * data,enum bmi160_sensor_type t,int * uscale)34977c4ad2dSDaniel Baluta int bmi160_get_scale(struct bmi160_data *data, enum bmi160_sensor_type t,
35077c4ad2dSDaniel Baluta 		     int *uscale)
35177c4ad2dSDaniel Baluta {
35277c4ad2dSDaniel Baluta 	int i, ret, val;
35377c4ad2dSDaniel Baluta 
35477c4ad2dSDaniel Baluta 	ret = regmap_read(data->regmap, bmi160_regs[t].range, &val);
35594edaac7SMartin Kelly 	if (ret)
35677c4ad2dSDaniel Baluta 		return ret;
35777c4ad2dSDaniel Baluta 
35877c4ad2dSDaniel Baluta 	for (i = 0; i < bmi160_scale_table[t].num; i++)
35977c4ad2dSDaniel Baluta 		if (bmi160_scale_table[t].tbl[i].bits == val) {
36077c4ad2dSDaniel Baluta 			*uscale = bmi160_scale_table[t].tbl[i].uscale;
36177c4ad2dSDaniel Baluta 			return 0;
36277c4ad2dSDaniel Baluta 		}
36377c4ad2dSDaniel Baluta 
36477c4ad2dSDaniel Baluta 	return -EINVAL;
36577c4ad2dSDaniel Baluta }
36677c4ad2dSDaniel Baluta 
bmi160_get_data(struct bmi160_data * data,int chan_type,int axis,int * val)36777c4ad2dSDaniel Baluta static int bmi160_get_data(struct bmi160_data *data, int chan_type,
36877c4ad2dSDaniel Baluta 			   int axis, int *val)
36977c4ad2dSDaniel Baluta {
37077c4ad2dSDaniel Baluta 	u8 reg;
37177c4ad2dSDaniel Baluta 	int ret;
37277c4ad2dSDaniel Baluta 	__le16 sample;
37377c4ad2dSDaniel Baluta 	enum bmi160_sensor_type t = bmi160_to_sensor(chan_type);
37477c4ad2dSDaniel Baluta 
3752d3f956eSAlison Schofield 	reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(sample);
37677c4ad2dSDaniel Baluta 
3772d3f956eSAlison Schofield 	ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(sample));
37894edaac7SMartin Kelly 	if (ret)
37977c4ad2dSDaniel Baluta 		return ret;
38077c4ad2dSDaniel Baluta 
38177c4ad2dSDaniel Baluta 	*val = sign_extend32(le16_to_cpu(sample), 15);
38277c4ad2dSDaniel Baluta 
38377c4ad2dSDaniel Baluta 	return 0;
38477c4ad2dSDaniel Baluta }
38577c4ad2dSDaniel Baluta 
38677c4ad2dSDaniel Baluta static
bmi160_set_odr(struct bmi160_data * data,enum bmi160_sensor_type t,int odr,int uodr)38777c4ad2dSDaniel Baluta int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t,
38877c4ad2dSDaniel Baluta 		   int odr, int uodr)
38977c4ad2dSDaniel Baluta {
39077c4ad2dSDaniel Baluta 	int i;
39177c4ad2dSDaniel Baluta 
39277c4ad2dSDaniel Baluta 	for (i = 0; i < bmi160_odr_table[t].num; i++)
39377c4ad2dSDaniel Baluta 		if (bmi160_odr_table[t].tbl[i].odr == odr &&
39477c4ad2dSDaniel Baluta 		    bmi160_odr_table[t].tbl[i].uodr == uodr)
39577c4ad2dSDaniel Baluta 			break;
39677c4ad2dSDaniel Baluta 
39777c4ad2dSDaniel Baluta 	if (i >= bmi160_odr_table[t].num)
39877c4ad2dSDaniel Baluta 		return -EINVAL;
39977c4ad2dSDaniel Baluta 
40077c4ad2dSDaniel Baluta 	return regmap_update_bits(data->regmap,
40177c4ad2dSDaniel Baluta 				  bmi160_regs[t].config,
402c25d3f37SDaniel Baluta 				  bmi160_regs[t].config_odr_mask,
403c25d3f37SDaniel Baluta 				  bmi160_odr_table[t].tbl[i].bits);
40477c4ad2dSDaniel Baluta }
40577c4ad2dSDaniel Baluta 
bmi160_get_odr(struct bmi160_data * data,enum bmi160_sensor_type t,int * odr,int * uodr)40677c4ad2dSDaniel Baluta static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t,
40777c4ad2dSDaniel Baluta 			  int *odr, int *uodr)
40877c4ad2dSDaniel Baluta {
40977c4ad2dSDaniel Baluta 	int i, val, ret;
41077c4ad2dSDaniel Baluta 
41177c4ad2dSDaniel Baluta 	ret = regmap_read(data->regmap, bmi160_regs[t].config, &val);
41294edaac7SMartin Kelly 	if (ret)
41377c4ad2dSDaniel Baluta 		return ret;
41477c4ad2dSDaniel Baluta 
41577c4ad2dSDaniel Baluta 	val &= bmi160_regs[t].config_odr_mask;
41677c4ad2dSDaniel Baluta 
41777c4ad2dSDaniel Baluta 	for (i = 0; i < bmi160_odr_table[t].num; i++)
41877c4ad2dSDaniel Baluta 		if (val == bmi160_odr_table[t].tbl[i].bits)
41977c4ad2dSDaniel Baluta 			break;
42077c4ad2dSDaniel Baluta 
42177c4ad2dSDaniel Baluta 	if (i >= bmi160_odr_table[t].num)
42277c4ad2dSDaniel Baluta 		return -EINVAL;
42377c4ad2dSDaniel Baluta 
42477c4ad2dSDaniel Baluta 	*odr = bmi160_odr_table[t].tbl[i].odr;
42577c4ad2dSDaniel Baluta 	*uodr = bmi160_odr_table[t].tbl[i].uodr;
42677c4ad2dSDaniel Baluta 
42777c4ad2dSDaniel Baluta 	return 0;
42877c4ad2dSDaniel Baluta }
42977c4ad2dSDaniel Baluta 
bmi160_trigger_handler(int irq,void * p)43077c4ad2dSDaniel Baluta static irqreturn_t bmi160_trigger_handler(int irq, void *p)
43177c4ad2dSDaniel Baluta {
43277c4ad2dSDaniel Baluta 	struct iio_poll_func *pf = p;
43377c4ad2dSDaniel Baluta 	struct iio_dev *indio_dev = pf->indio_dev;
43477c4ad2dSDaniel Baluta 	struct bmi160_data *data = iio_priv(indio_dev);
43577c4ad2dSDaniel Baluta 	int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L;
43677c4ad2dSDaniel Baluta 	__le16 sample;
43777c4ad2dSDaniel Baluta 
438*39a1e2f3SNuno Sa 	iio_for_each_active_channel(indio_dev, i) {
4392d3f956eSAlison Schofield 		ret = regmap_bulk_read(data->regmap, base + i * sizeof(sample),
4402d3f956eSAlison Schofield 				       &sample, sizeof(sample));
44194edaac7SMartin Kelly 		if (ret)
44277c4ad2dSDaniel Baluta 			goto done;
4437b6b5123SJonathan Cameron 		data->buf[j++] = sample;
44477c4ad2dSDaniel Baluta 	}
44577c4ad2dSDaniel Baluta 
4467b6b5123SJonathan Cameron 	iio_push_to_buffers_with_timestamp(indio_dev, data->buf, pf->timestamp);
44777c4ad2dSDaniel Baluta done:
44877c4ad2dSDaniel Baluta 	iio_trigger_notify_done(indio_dev->trig);
44977c4ad2dSDaniel Baluta 	return IRQ_HANDLED;
45077c4ad2dSDaniel Baluta }
45177c4ad2dSDaniel Baluta 
bmi160_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)45277c4ad2dSDaniel Baluta static int bmi160_read_raw(struct iio_dev *indio_dev,
45377c4ad2dSDaniel Baluta 			   struct iio_chan_spec const *chan,
45477c4ad2dSDaniel Baluta 			   int *val, int *val2, long mask)
45577c4ad2dSDaniel Baluta {
45677c4ad2dSDaniel Baluta 	int ret;
45777c4ad2dSDaniel Baluta 	struct bmi160_data *data = iio_priv(indio_dev);
45877c4ad2dSDaniel Baluta 
45977c4ad2dSDaniel Baluta 	switch (mask) {
46077c4ad2dSDaniel Baluta 	case IIO_CHAN_INFO_RAW:
46177c4ad2dSDaniel Baluta 		ret = bmi160_get_data(data, chan->type, chan->channel2, val);
46294edaac7SMartin Kelly 		if (ret)
46377c4ad2dSDaniel Baluta 			return ret;
46477c4ad2dSDaniel Baluta 		return IIO_VAL_INT;
46577c4ad2dSDaniel Baluta 	case IIO_CHAN_INFO_SCALE:
46677c4ad2dSDaniel Baluta 		*val = 0;
46777c4ad2dSDaniel Baluta 		ret = bmi160_get_scale(data,
46877c4ad2dSDaniel Baluta 				       bmi160_to_sensor(chan->type), val2);
46994edaac7SMartin Kelly 		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
47077c4ad2dSDaniel Baluta 	case IIO_CHAN_INFO_SAMP_FREQ:
47177c4ad2dSDaniel Baluta 		ret = bmi160_get_odr(data, bmi160_to_sensor(chan->type),
47277c4ad2dSDaniel Baluta 				     val, val2);
47394edaac7SMartin Kelly 		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
47477c4ad2dSDaniel Baluta 	default:
47577c4ad2dSDaniel Baluta 		return -EINVAL;
47677c4ad2dSDaniel Baluta 	}
47777c4ad2dSDaniel Baluta 
47877c4ad2dSDaniel Baluta 	return 0;
47977c4ad2dSDaniel Baluta }
48077c4ad2dSDaniel Baluta 
bmi160_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)48177c4ad2dSDaniel Baluta static int bmi160_write_raw(struct iio_dev *indio_dev,
48277c4ad2dSDaniel Baluta 			    struct iio_chan_spec const *chan,
48377c4ad2dSDaniel Baluta 			    int val, int val2, long mask)
48477c4ad2dSDaniel Baluta {
48577c4ad2dSDaniel Baluta 	struct bmi160_data *data = iio_priv(indio_dev);
48677c4ad2dSDaniel Baluta 
48777c4ad2dSDaniel Baluta 	switch (mask) {
48877c4ad2dSDaniel Baluta 	case IIO_CHAN_INFO_SCALE:
48977c4ad2dSDaniel Baluta 		return bmi160_set_scale(data,
49077c4ad2dSDaniel Baluta 					bmi160_to_sensor(chan->type), val2);
49177c4ad2dSDaniel Baluta 	case IIO_CHAN_INFO_SAMP_FREQ:
49277c4ad2dSDaniel Baluta 		return bmi160_set_odr(data, bmi160_to_sensor(chan->type),
49377c4ad2dSDaniel Baluta 				      val, val2);
49477c4ad2dSDaniel Baluta 	default:
49577c4ad2dSDaniel Baluta 		return -EINVAL;
49677c4ad2dSDaniel Baluta 	}
49777c4ad2dSDaniel Baluta 
49877c4ad2dSDaniel Baluta 	return 0;
49977c4ad2dSDaniel Baluta }
50077c4ad2dSDaniel Baluta 
501216912e3SDaniel Baluta static
502216912e3SDaniel Baluta IIO_CONST_ATTR(in_accel_sampling_frequency_available,
503216912e3SDaniel Baluta 	       "0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600");
504216912e3SDaniel Baluta static
505216912e3SDaniel Baluta IIO_CONST_ATTR(in_anglvel_sampling_frequency_available,
506216912e3SDaniel Baluta 	       "25 50 100 200 400 800 1600 3200");
507216912e3SDaniel Baluta static
508216912e3SDaniel Baluta IIO_CONST_ATTR(in_accel_scale_available,
509216912e3SDaniel Baluta 	       "0.000598 0.001197 0.002394 0.004788");
510216912e3SDaniel Baluta static
511216912e3SDaniel Baluta IIO_CONST_ATTR(in_anglvel_scale_available,
512216912e3SDaniel Baluta 	       "0.001065 0.000532 0.000266 0.000133 0.000066");
513216912e3SDaniel Baluta 
514216912e3SDaniel Baluta static struct attribute *bmi160_attrs[] = {
515216912e3SDaniel Baluta 	&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
516216912e3SDaniel Baluta 	&iio_const_attr_in_anglvel_sampling_frequency_available.dev_attr.attr,
517216912e3SDaniel Baluta 	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
518216912e3SDaniel Baluta 	&iio_const_attr_in_anglvel_scale_available.dev_attr.attr,
519216912e3SDaniel Baluta 	NULL,
520216912e3SDaniel Baluta };
521216912e3SDaniel Baluta 
522216912e3SDaniel Baluta static const struct attribute_group bmi160_attrs_group = {
523216912e3SDaniel Baluta 	.attrs = bmi160_attrs,
524216912e3SDaniel Baluta };
525216912e3SDaniel Baluta 
52677c4ad2dSDaniel Baluta static const struct iio_info bmi160_info = {
52777c4ad2dSDaniel Baluta 	.read_raw = bmi160_read_raw,
52877c4ad2dSDaniel Baluta 	.write_raw = bmi160_write_raw,
529216912e3SDaniel Baluta 	.attrs = &bmi160_attrs_group,
53077c4ad2dSDaniel Baluta };
53177c4ad2dSDaniel Baluta 
bmi160_write_conf_reg(struct regmap * regmap,unsigned int reg,unsigned int mask,unsigned int bits,unsigned int write_usleep)532895bf81eSMartin Kelly static int bmi160_write_conf_reg(struct regmap *regmap, unsigned int reg,
533895bf81eSMartin Kelly 				 unsigned int mask, unsigned int bits,
534895bf81eSMartin Kelly 				 unsigned int write_usleep)
535895bf81eSMartin Kelly {
536895bf81eSMartin Kelly 	int ret;
537895bf81eSMartin Kelly 	unsigned int val;
538895bf81eSMartin Kelly 
539895bf81eSMartin Kelly 	ret = regmap_read(regmap, reg, &val);
540895bf81eSMartin Kelly 	if (ret)
541895bf81eSMartin Kelly 		return ret;
542895bf81eSMartin Kelly 
543895bf81eSMartin Kelly 	val = (val & ~mask) | bits;
544895bf81eSMartin Kelly 
545895bf81eSMartin Kelly 	ret = regmap_write(regmap, reg, val);
546895bf81eSMartin Kelly 	if (ret)
547895bf81eSMartin Kelly 		return ret;
548895bf81eSMartin Kelly 
549895bf81eSMartin Kelly 	/*
550895bf81eSMartin Kelly 	 * We need to wait after writing before we can write again. See the
551895bf81eSMartin Kelly 	 * datasheet, page 93.
552895bf81eSMartin Kelly 	 */
553895bf81eSMartin Kelly 	usleep_range(write_usleep, write_usleep + 1000);
554895bf81eSMartin Kelly 
555895bf81eSMartin Kelly 	return 0;
556895bf81eSMartin Kelly }
557895bf81eSMartin Kelly 
bmi160_config_pin(struct regmap * regmap,enum bmi160_int_pin pin,bool open_drain,u8 irq_mask,unsigned long write_usleep)558895bf81eSMartin Kelly static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin,
559895bf81eSMartin Kelly 			     bool open_drain, u8 irq_mask,
560895bf81eSMartin Kelly 			     unsigned long write_usleep)
561895bf81eSMartin Kelly {
562895bf81eSMartin Kelly 	int ret;
563895bf81eSMartin Kelly 	struct device *dev = regmap_get_device(regmap);
564895bf81eSMartin Kelly 	u8 int_out_ctrl_shift;
565895bf81eSMartin Kelly 	u8 int_latch_mask;
566895bf81eSMartin Kelly 	u8 int_map_mask;
567895bf81eSMartin Kelly 	u8 int_out_ctrl_mask;
568895bf81eSMartin Kelly 	u8 int_out_ctrl_bits;
569895bf81eSMartin Kelly 	const char *pin_name;
570895bf81eSMartin Kelly 
571895bf81eSMartin Kelly 	switch (pin) {
572895bf81eSMartin Kelly 	case BMI160_PIN_INT1:
573895bf81eSMartin Kelly 		int_out_ctrl_shift = BMI160_INT1_OUT_CTRL_SHIFT;
574895bf81eSMartin Kelly 		int_latch_mask = BMI160_INT1_LATCH_MASK;
575895bf81eSMartin Kelly 		int_map_mask = BMI160_INT1_MAP_DRDY_EN;
576895bf81eSMartin Kelly 		break;
577895bf81eSMartin Kelly 	case BMI160_PIN_INT2:
578895bf81eSMartin Kelly 		int_out_ctrl_shift = BMI160_INT2_OUT_CTRL_SHIFT;
579895bf81eSMartin Kelly 		int_latch_mask = BMI160_INT2_LATCH_MASK;
580895bf81eSMartin Kelly 		int_map_mask = BMI160_INT2_MAP_DRDY_EN;
581895bf81eSMartin Kelly 		break;
582895bf81eSMartin Kelly 	}
583895bf81eSMartin Kelly 	int_out_ctrl_mask = BMI160_INT_OUT_CTRL_MASK << int_out_ctrl_shift;
584895bf81eSMartin Kelly 
585895bf81eSMartin Kelly 	/*
586895bf81eSMartin Kelly 	 * Enable the requested pin with the right settings:
587895bf81eSMartin Kelly 	 * - Push-pull/open-drain
588895bf81eSMartin Kelly 	 * - Active low/high
589895bf81eSMartin Kelly 	 * - Edge/level triggered
590895bf81eSMartin Kelly 	 */
591895bf81eSMartin Kelly 	int_out_ctrl_bits = BMI160_OUTPUT_EN;
592895bf81eSMartin Kelly 	if (open_drain)
593895bf81eSMartin Kelly 		/* Default is push-pull. */
594895bf81eSMartin Kelly 		int_out_ctrl_bits |= BMI160_OPEN_DRAIN;
595895bf81eSMartin Kelly 	int_out_ctrl_bits |= irq_mask;
596895bf81eSMartin Kelly 	int_out_ctrl_bits <<= int_out_ctrl_shift;
597895bf81eSMartin Kelly 
598895bf81eSMartin Kelly 	ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_OUT_CTRL,
599895bf81eSMartin Kelly 				    int_out_ctrl_mask, int_out_ctrl_bits,
600895bf81eSMartin Kelly 				    write_usleep);
601895bf81eSMartin Kelly 	if (ret)
602895bf81eSMartin Kelly 		return ret;
603895bf81eSMartin Kelly 
604895bf81eSMartin Kelly 	/* Set the pin to input mode with no latching. */
605895bf81eSMartin Kelly 	ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_LATCH,
606895bf81eSMartin Kelly 				    int_latch_mask, int_latch_mask,
607895bf81eSMartin Kelly 				    write_usleep);
608895bf81eSMartin Kelly 	if (ret)
609895bf81eSMartin Kelly 		return ret;
610895bf81eSMartin Kelly 
611895bf81eSMartin Kelly 	/* Map interrupts to the requested pin. */
612895bf81eSMartin Kelly 	ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_MAP,
613895bf81eSMartin Kelly 				    int_map_mask, int_map_mask,
614895bf81eSMartin Kelly 				    write_usleep);
615895bf81eSMartin Kelly 	if (ret) {
616895bf81eSMartin Kelly 		switch (pin) {
617895bf81eSMartin Kelly 		case BMI160_PIN_INT1:
618895bf81eSMartin Kelly 			pin_name = "INT1";
619895bf81eSMartin Kelly 			break;
620895bf81eSMartin Kelly 		case BMI160_PIN_INT2:
621895bf81eSMartin Kelly 			pin_name = "INT2";
622895bf81eSMartin Kelly 			break;
623895bf81eSMartin Kelly 		}
624895bf81eSMartin Kelly 		dev_err(dev, "Failed to configure %s IRQ pin", pin_name);
625895bf81eSMartin Kelly 	}
626895bf81eSMartin Kelly 
627895bf81eSMartin Kelly 	return ret;
628895bf81eSMartin Kelly }
629895bf81eSMartin Kelly 
bmi160_enable_irq(struct regmap * regmap,bool enable)630895bf81eSMartin Kelly int bmi160_enable_irq(struct regmap *regmap, bool enable)
631895bf81eSMartin Kelly {
632895bf81eSMartin Kelly 	unsigned int enable_bit = 0;
633895bf81eSMartin Kelly 
634895bf81eSMartin Kelly 	if (enable)
635895bf81eSMartin Kelly 		enable_bit = BMI160_DRDY_INT_EN;
636895bf81eSMartin Kelly 
637895bf81eSMartin Kelly 	return bmi160_write_conf_reg(regmap, BMI160_REG_INT_EN,
638895bf81eSMartin Kelly 				     BMI160_DRDY_INT_EN, enable_bit,
639895bf81eSMartin Kelly 				     BMI160_NORMAL_WRITE_USLEEP);
640895bf81eSMartin Kelly }
6412a8efd8bSJonathan Cameron EXPORT_SYMBOL_NS(bmi160_enable_irq, IIO_BMI160);
642895bf81eSMartin Kelly 
bmi160_get_irq(struct fwnode_handle * fwnode,enum bmi160_int_pin * pin)6435f474919SAndy Shevchenko static int bmi160_get_irq(struct fwnode_handle *fwnode, enum bmi160_int_pin *pin)
644895bf81eSMartin Kelly {
645895bf81eSMartin Kelly 	int irq;
646895bf81eSMartin Kelly 
647895bf81eSMartin Kelly 	/* Use INT1 if possible, otherwise fall back to INT2. */
6485f474919SAndy Shevchenko 	irq = fwnode_irq_get_byname(fwnode, "INT1");
649895bf81eSMartin Kelly 	if (irq > 0) {
650895bf81eSMartin Kelly 		*pin = BMI160_PIN_INT1;
651895bf81eSMartin Kelly 		return irq;
652895bf81eSMartin Kelly 	}
653895bf81eSMartin Kelly 
6545f474919SAndy Shevchenko 	irq = fwnode_irq_get_byname(fwnode, "INT2");
655895bf81eSMartin Kelly 	if (irq > 0)
656895bf81eSMartin Kelly 		*pin = BMI160_PIN_INT2;
657895bf81eSMartin Kelly 
658895bf81eSMartin Kelly 	return irq;
659895bf81eSMartin Kelly }
660895bf81eSMartin Kelly 
bmi160_config_device_irq(struct iio_dev * indio_dev,int irq_type,enum bmi160_int_pin pin)661895bf81eSMartin Kelly static int bmi160_config_device_irq(struct iio_dev *indio_dev, int irq_type,
662895bf81eSMartin Kelly 				    enum bmi160_int_pin pin)
663895bf81eSMartin Kelly {
664895bf81eSMartin Kelly 	bool open_drain;
665895bf81eSMartin Kelly 	u8 irq_mask;
666895bf81eSMartin Kelly 	struct bmi160_data *data = iio_priv(indio_dev);
667895bf81eSMartin Kelly 	struct device *dev = regmap_get_device(data->regmap);
668895bf81eSMartin Kelly 
669895bf81eSMartin Kelly 	/* Level-triggered, active-low is the default if we set all zeroes. */
670895bf81eSMartin Kelly 	if (irq_type == IRQF_TRIGGER_RISING)
671895bf81eSMartin Kelly 		irq_mask = BMI160_ACTIVE_HIGH | BMI160_EDGE_TRIGGERED;
672895bf81eSMartin Kelly 	else if (irq_type == IRQF_TRIGGER_FALLING)
673895bf81eSMartin Kelly 		irq_mask = BMI160_EDGE_TRIGGERED;
674895bf81eSMartin Kelly 	else if (irq_type == IRQF_TRIGGER_HIGH)
675895bf81eSMartin Kelly 		irq_mask = BMI160_ACTIVE_HIGH;
676895bf81eSMartin Kelly 	else if (irq_type == IRQF_TRIGGER_LOW)
677895bf81eSMartin Kelly 		irq_mask = 0;
678895bf81eSMartin Kelly 	else {
679895bf81eSMartin Kelly 		dev_err(&indio_dev->dev,
680895bf81eSMartin Kelly 			"Invalid interrupt type 0x%x specified\n", irq_type);
681895bf81eSMartin Kelly 		return -EINVAL;
682895bf81eSMartin Kelly 	}
683895bf81eSMartin Kelly 
6845f474919SAndy Shevchenko 	open_drain = device_property_read_bool(dev, "drive-open-drain");
685895bf81eSMartin Kelly 
686895bf81eSMartin Kelly 	return bmi160_config_pin(data->regmap, pin, open_drain, irq_mask,
687895bf81eSMartin Kelly 				 BMI160_NORMAL_WRITE_USLEEP);
688895bf81eSMartin Kelly }
689895bf81eSMartin Kelly 
bmi160_setup_irq(struct iio_dev * indio_dev,int irq,enum bmi160_int_pin pin)690895bf81eSMartin Kelly static int bmi160_setup_irq(struct iio_dev *indio_dev, int irq,
691895bf81eSMartin Kelly 			    enum bmi160_int_pin pin)
692895bf81eSMartin Kelly {
693895bf81eSMartin Kelly 	struct irq_data *desc;
694895bf81eSMartin Kelly 	u32 irq_type;
695895bf81eSMartin Kelly 	int ret;
696895bf81eSMartin Kelly 
697895bf81eSMartin Kelly 	desc = irq_get_irq_data(irq);
698895bf81eSMartin Kelly 	if (!desc) {
699895bf81eSMartin Kelly 		dev_err(&indio_dev->dev, "Could not find IRQ %d\n", irq);
700895bf81eSMartin Kelly 		return -EINVAL;
701895bf81eSMartin Kelly 	}
702895bf81eSMartin Kelly 
703895bf81eSMartin Kelly 	irq_type = irqd_get_trigger_type(desc);
704895bf81eSMartin Kelly 
705895bf81eSMartin Kelly 	ret = bmi160_config_device_irq(indio_dev, irq_type, pin);
706895bf81eSMartin Kelly 	if (ret)
707895bf81eSMartin Kelly 		return ret;
708895bf81eSMartin Kelly 
709895bf81eSMartin Kelly 	return bmi160_probe_trigger(indio_dev, irq, irq_type);
710895bf81eSMartin Kelly }
711895bf81eSMartin Kelly 
bmi160_check_chip_id(const u8 chip_id)712cedb9bd8SDanila Tikhonov static int bmi160_check_chip_id(const u8 chip_id)
713cedb9bd8SDanila Tikhonov {
714cedb9bd8SDanila Tikhonov 	for (int i = 0; i < ARRAY_SIZE(bmi_chip_ids); i++) {
715cedb9bd8SDanila Tikhonov 		if (chip_id == bmi_chip_ids[i])
716cedb9bd8SDanila Tikhonov 			return 0;
717cedb9bd8SDanila Tikhonov 	}
718cedb9bd8SDanila Tikhonov 
719cedb9bd8SDanila Tikhonov 	return -ENODEV;
720cedb9bd8SDanila Tikhonov }
721cedb9bd8SDanila Tikhonov 
bmi160_chip_init(struct bmi160_data * data,bool use_spi)72277c4ad2dSDaniel Baluta static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
72377c4ad2dSDaniel Baluta {
72477c4ad2dSDaniel Baluta 	int ret;
72577c4ad2dSDaniel Baluta 	unsigned int val;
72677c4ad2dSDaniel Baluta 	struct device *dev = regmap_get_device(data->regmap);
72777c4ad2dSDaniel Baluta 
7285dea3fb0SJonathan Albrieux 	ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
7295dea3fb0SJonathan Albrieux 	if (ret) {
7305dea3fb0SJonathan Albrieux 		dev_err(dev, "Failed to enable regulators: %d\n", ret);
7315dea3fb0SJonathan Albrieux 		return ret;
7325dea3fb0SJonathan Albrieux 	}
7335dea3fb0SJonathan Albrieux 
73477c4ad2dSDaniel Baluta 	ret = regmap_write(data->regmap, BMI160_REG_CMD, BMI160_CMD_SOFTRESET);
73594edaac7SMartin Kelly 	if (ret)
736d926054dSTong Zhang 		goto disable_regulator;
73777c4ad2dSDaniel Baluta 
73877c4ad2dSDaniel Baluta 	usleep_range(BMI160_SOFTRESET_USLEEP, BMI160_SOFTRESET_USLEEP + 1);
73977c4ad2dSDaniel Baluta 
74077c4ad2dSDaniel Baluta 	/*
74177c4ad2dSDaniel Baluta 	 * CS rising edge is needed before starting SPI, so do a dummy read
74277c4ad2dSDaniel Baluta 	 * See Section 3.2.1, page 86 of the datasheet
74377c4ad2dSDaniel Baluta 	 */
74477c4ad2dSDaniel Baluta 	if (use_spi) {
74577c4ad2dSDaniel Baluta 		ret = regmap_read(data->regmap, BMI160_REG_DUMMY, &val);
74694edaac7SMartin Kelly 		if (ret)
747d926054dSTong Zhang 			goto disable_regulator;
74877c4ad2dSDaniel Baluta 	}
74977c4ad2dSDaniel Baluta 
75077c4ad2dSDaniel Baluta 	ret = regmap_read(data->regmap, BMI160_REG_CHIP_ID, &val);
75194edaac7SMartin Kelly 	if (ret) {
75277c4ad2dSDaniel Baluta 		dev_err(dev, "Error reading chip id\n");
753d926054dSTong Zhang 		goto disable_regulator;
75477c4ad2dSDaniel Baluta 	}
755cedb9bd8SDanila Tikhonov 
756cedb9bd8SDanila Tikhonov 	ret = bmi160_check_chip_id(val);
757cedb9bd8SDanila Tikhonov 	if (ret)
758cedb9bd8SDanila Tikhonov 		dev_warn(dev, "Chip id not found: %x\n", val);
75977c4ad2dSDaniel Baluta 
76077c4ad2dSDaniel Baluta 	ret = bmi160_set_mode(data, BMI160_ACCEL, true);
76194edaac7SMartin Kelly 	if (ret)
762d926054dSTong Zhang 		goto disable_regulator;
76377c4ad2dSDaniel Baluta 
76477c4ad2dSDaniel Baluta 	ret = bmi160_set_mode(data, BMI160_GYRO, true);
76594edaac7SMartin Kelly 	if (ret)
766d926054dSTong Zhang 		goto disable_accel;
76777c4ad2dSDaniel Baluta 
76877c4ad2dSDaniel Baluta 	return 0;
769d926054dSTong Zhang 
770d926054dSTong Zhang disable_accel:
771d926054dSTong Zhang 	bmi160_set_mode(data, BMI160_ACCEL, false);
772d926054dSTong Zhang 
773d926054dSTong Zhang disable_regulator:
774d926054dSTong Zhang 	regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
775d926054dSTong Zhang 	return ret;
77677c4ad2dSDaniel Baluta }
77777c4ad2dSDaniel Baluta 
bmi160_data_rdy_trigger_set_state(struct iio_trigger * trig,bool enable)778895bf81eSMartin Kelly static int bmi160_data_rdy_trigger_set_state(struct iio_trigger *trig,
779895bf81eSMartin Kelly 					     bool enable)
780895bf81eSMartin Kelly {
781895bf81eSMartin Kelly 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
782895bf81eSMartin Kelly 	struct bmi160_data *data = iio_priv(indio_dev);
783895bf81eSMartin Kelly 
784895bf81eSMartin Kelly 	return bmi160_enable_irq(data->regmap, enable);
785895bf81eSMartin Kelly }
786895bf81eSMartin Kelly 
787895bf81eSMartin Kelly static const struct iio_trigger_ops bmi160_trigger_ops = {
788895bf81eSMartin Kelly 	.set_trigger_state = &bmi160_data_rdy_trigger_set_state,
789895bf81eSMartin Kelly };
790895bf81eSMartin Kelly 
bmi160_probe_trigger(struct iio_dev * indio_dev,int irq,u32 irq_type)791895bf81eSMartin Kelly int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type)
792895bf81eSMartin Kelly {
793895bf81eSMartin Kelly 	struct bmi160_data *data = iio_priv(indio_dev);
794895bf81eSMartin Kelly 	int ret;
795895bf81eSMartin Kelly 
796895bf81eSMartin Kelly 	data->trig = devm_iio_trigger_alloc(&indio_dev->dev, "%s-dev%d",
79715ea2878SJonathan Cameron 					    indio_dev->name,
79815ea2878SJonathan Cameron 					    iio_device_id(indio_dev));
799895bf81eSMartin Kelly 
800895bf81eSMartin Kelly 	if (data->trig == NULL)
801895bf81eSMartin Kelly 		return -ENOMEM;
802895bf81eSMartin Kelly 
803895bf81eSMartin Kelly 	ret = devm_request_irq(&indio_dev->dev, irq,
804895bf81eSMartin Kelly 			       &iio_trigger_generic_data_rdy_poll,
805895bf81eSMartin Kelly 			       irq_type, "bmi160", data->trig);
80694edaac7SMartin Kelly 	if (ret)
807895bf81eSMartin Kelly 		return ret;
808895bf81eSMartin Kelly 
809895bf81eSMartin Kelly 	data->trig->dev.parent = regmap_get_device(data->regmap);
810895bf81eSMartin Kelly 	data->trig->ops = &bmi160_trigger_ops;
811895bf81eSMartin Kelly 	iio_trigger_set_drvdata(data->trig, indio_dev);
812895bf81eSMartin Kelly 
813895bf81eSMartin Kelly 	ret = devm_iio_trigger_register(&indio_dev->dev, data->trig);
814895bf81eSMartin Kelly 	if (ret)
815895bf81eSMartin Kelly 		return ret;
816895bf81eSMartin Kelly 
817895bf81eSMartin Kelly 	indio_dev->trig = iio_trigger_get(data->trig);
818895bf81eSMartin Kelly 
819895bf81eSMartin Kelly 	return 0;
820895bf81eSMartin Kelly }
821895bf81eSMartin Kelly 
bmi160_chip_uninit(void * data)8226e998291SMartin Kelly static void bmi160_chip_uninit(void *data)
82377c4ad2dSDaniel Baluta {
8246e998291SMartin Kelly 	struct bmi160_data *bmi_data = data;
8255dea3fb0SJonathan Albrieux 	struct device *dev = regmap_get_device(bmi_data->regmap);
8265dea3fb0SJonathan Albrieux 	int ret;
8276e998291SMartin Kelly 
8286e998291SMartin Kelly 	bmi160_set_mode(bmi_data, BMI160_GYRO, false);
8296e998291SMartin Kelly 	bmi160_set_mode(bmi_data, BMI160_ACCEL, false);
8305dea3fb0SJonathan Albrieux 
8315dea3fb0SJonathan Albrieux 	ret = regulator_bulk_disable(ARRAY_SIZE(bmi_data->supplies),
8325dea3fb0SJonathan Albrieux 				     bmi_data->supplies);
8335dea3fb0SJonathan Albrieux 	if (ret)
8345dea3fb0SJonathan Albrieux 		dev_err(dev, "Failed to disable regulators: %d\n", ret);
83577c4ad2dSDaniel Baluta }
83677c4ad2dSDaniel Baluta 
bmi160_core_probe(struct device * dev,struct regmap * regmap,const char * name,bool use_spi)83777c4ad2dSDaniel Baluta int bmi160_core_probe(struct device *dev, struct regmap *regmap,
83877c4ad2dSDaniel Baluta 		      const char *name, bool use_spi)
83977c4ad2dSDaniel Baluta {
84077c4ad2dSDaniel Baluta 	struct iio_dev *indio_dev;
84177c4ad2dSDaniel Baluta 	struct bmi160_data *data;
842895bf81eSMartin Kelly 	int irq;
843895bf81eSMartin Kelly 	enum bmi160_int_pin int_pin;
84477c4ad2dSDaniel Baluta 	int ret;
84577c4ad2dSDaniel Baluta 
84677c4ad2dSDaniel Baluta 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
84777c4ad2dSDaniel Baluta 	if (!indio_dev)
84877c4ad2dSDaniel Baluta 		return -ENOMEM;
84977c4ad2dSDaniel Baluta 
85077c4ad2dSDaniel Baluta 	data = iio_priv(indio_dev);
85177c4ad2dSDaniel Baluta 	dev_set_drvdata(dev, indio_dev);
85277c4ad2dSDaniel Baluta 	data->regmap = regmap;
85377c4ad2dSDaniel Baluta 
8545dea3fb0SJonathan Albrieux 	data->supplies[0].supply = "vdd";
8555dea3fb0SJonathan Albrieux 	data->supplies[1].supply = "vddio";
8565dea3fb0SJonathan Albrieux 	ret = devm_regulator_bulk_get(dev,
8575dea3fb0SJonathan Albrieux 				      ARRAY_SIZE(data->supplies),
8585dea3fb0SJonathan Albrieux 				      data->supplies);
8595dea3fb0SJonathan Albrieux 	if (ret) {
8605dea3fb0SJonathan Albrieux 		dev_err(dev, "Failed to get regulators: %d\n", ret);
8615dea3fb0SJonathan Albrieux 		return ret;
8625dea3fb0SJonathan Albrieux 	}
8635dea3fb0SJonathan Albrieux 
864b892770aSAndy Shevchenko 	ret = iio_read_mount_matrix(dev, &data->orientation);
865812a46b7SJonathan Albrieux 	if (ret)
866812a46b7SJonathan Albrieux 		return ret;
867812a46b7SJonathan Albrieux 
86877c4ad2dSDaniel Baluta 	ret = bmi160_chip_init(data, use_spi);
86994edaac7SMartin Kelly 	if (ret)
87077c4ad2dSDaniel Baluta 		return ret;
87177c4ad2dSDaniel Baluta 
8726e998291SMartin Kelly 	ret = devm_add_action_or_reset(dev, bmi160_chip_uninit, data);
87394edaac7SMartin Kelly 	if (ret)
8746e998291SMartin Kelly 		return ret;
8756e998291SMartin Kelly 
87677c4ad2dSDaniel Baluta 	indio_dev->channels = bmi160_channels;
87777c4ad2dSDaniel Baluta 	indio_dev->num_channels = ARRAY_SIZE(bmi160_channels);
87877c4ad2dSDaniel Baluta 	indio_dev->name = name;
87977c4ad2dSDaniel Baluta 	indio_dev->modes = INDIO_DIRECT_MODE;
88077c4ad2dSDaniel Baluta 	indio_dev->info = &bmi160_info;
88177c4ad2dSDaniel Baluta 
8820a3f50e4SMartin Kelly 	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
8830a3f50e4SMartin Kelly 					      iio_pollfunc_store_time,
88477c4ad2dSDaniel Baluta 					      bmi160_trigger_handler, NULL);
88594edaac7SMartin Kelly 	if (ret)
8866e998291SMartin Kelly 		return ret;
88777c4ad2dSDaniel Baluta 
8885f474919SAndy Shevchenko 	irq = bmi160_get_irq(dev_fwnode(dev), &int_pin);
889895bf81eSMartin Kelly 	if (irq > 0) {
890895bf81eSMartin Kelly 		ret = bmi160_setup_irq(indio_dev, irq, int_pin);
891895bf81eSMartin Kelly 		if (ret)
892895bf81eSMartin Kelly 			dev_err(&indio_dev->dev, "Failed to setup IRQ %d\n",
893895bf81eSMartin Kelly 				irq);
894895bf81eSMartin Kelly 	} else {
895895bf81eSMartin Kelly 		dev_info(&indio_dev->dev, "Not setting up IRQ trigger\n");
896895bf81eSMartin Kelly 	}
897895bf81eSMartin Kelly 
89894edaac7SMartin Kelly 	return devm_iio_device_register(dev, indio_dev);
89977c4ad2dSDaniel Baluta }
9002a8efd8bSJonathan Cameron EXPORT_SYMBOL_NS_GPL(bmi160_core_probe, IIO_BMI160);
90177c4ad2dSDaniel Baluta 
902fb774966SJonathan Albrieux MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
90377c4ad2dSDaniel Baluta MODULE_DESCRIPTION("Bosch BMI160 driver");
90477c4ad2dSDaniel Baluta MODULE_LICENSE("GPL v2");
905