162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * 3-axis accelerometer driver supporting many Bosch-Sensortec chips
462306a36Sopenharmony_ci * Copyright (c) 2014, Intel Corporation.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/i2c.h>
962306a36Sopenharmony_ci#include <linux/interrupt.h>
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/acpi.h>
1362306a36Sopenharmony_ci#include <linux/of_irq.h>
1462306a36Sopenharmony_ci#include <linux/pm.h>
1562306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1662306a36Sopenharmony_ci#include <linux/iio/iio.h>
1762306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
1862306a36Sopenharmony_ci#include <linux/iio/buffer.h>
1962306a36Sopenharmony_ci#include <linux/iio/events.h>
2062306a36Sopenharmony_ci#include <linux/iio/trigger.h>
2162306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
2262306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
2362306a36Sopenharmony_ci#include <linux/regmap.h>
2462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "bmc150-accel.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define BMC150_ACCEL_DRV_NAME			"bmc150_accel"
2962306a36Sopenharmony_ci#define BMC150_ACCEL_IRQ_NAME			"bmc150_accel_event"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define BMC150_ACCEL_REG_CHIP_ID		0x00
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_STATUS_2		0x0B
3462306a36Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_MASK		0x07
3562306a36Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_BIT_X		BIT(0)
3662306a36Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_BIT_Y		BIT(1)
3762306a36Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_BIT_Z		BIT(2)
3862306a36Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_BIT_SIGN	BIT(3)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define BMC150_ACCEL_REG_PMU_LPW		0x11
4162306a36Sopenharmony_ci#define BMC150_ACCEL_PMU_MODE_MASK		0xE0
4262306a36Sopenharmony_ci#define BMC150_ACCEL_PMU_MODE_SHIFT		5
4362306a36Sopenharmony_ci#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_MASK	0x17
4462306a36Sopenharmony_ci#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT	1
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define BMC150_ACCEL_REG_PMU_RANGE		0x0F
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define BMC150_ACCEL_DEF_RANGE_2G		0x03
4962306a36Sopenharmony_ci#define BMC150_ACCEL_DEF_RANGE_4G		0x05
5062306a36Sopenharmony_ci#define BMC150_ACCEL_DEF_RANGE_8G		0x08
5162306a36Sopenharmony_ci#define BMC150_ACCEL_DEF_RANGE_16G		0x0C
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Default BW: 125Hz */
5462306a36Sopenharmony_ci#define BMC150_ACCEL_REG_PMU_BW		0x10
5562306a36Sopenharmony_ci#define BMC150_ACCEL_DEF_BW			125
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define BMC150_ACCEL_REG_RESET			0x14
5862306a36Sopenharmony_ci#define BMC150_ACCEL_RESET_VAL			0xB6
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_MAP_0		0x19
6162306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE	BIT(2)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_MAP_1		0x1A
6462306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA	BIT(0)
6562306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM	BIT(1)
6662306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FFULL	BIT(2)
6762306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FFULL	BIT(5)
6862306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM	BIT(6)
6962306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA	BIT(7)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_MAP_2		0x1B
7262306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE	BIT(2)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_RST_LATCH		0x21
7562306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MODE_LATCH_RESET	0x80
7662306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MODE_LATCH_INT	0x0F
7762306a36Sopenharmony_ci#define BMC150_ACCEL_INT_MODE_NON_LATCH_INT	0x00
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_EN_0		0x16
8062306a36Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_SLP_X		BIT(0)
8162306a36Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_SLP_Y		BIT(1)
8262306a36Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_SLP_Z		BIT(2)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_EN_1		0x17
8562306a36Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_DATA_EN		BIT(4)
8662306a36Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN	BIT(5)
8762306a36Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_FWM_EN		BIT(6)
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_OUT_CTRL		0x20
9062306a36Sopenharmony_ci#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL	BIT(0)
9162306a36Sopenharmony_ci#define BMC150_ACCEL_INT_OUT_CTRL_INT2_LVL	BIT(2)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_5			0x27
9462306a36Sopenharmony_ci#define BMC150_ACCEL_SLOPE_DUR_MASK		0x03
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define BMC150_ACCEL_REG_INT_6			0x28
9762306a36Sopenharmony_ci#define BMC150_ACCEL_SLOPE_THRES_MASK		0xFF
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* Slope duration in terms of number of samples */
10062306a36Sopenharmony_ci#define BMC150_ACCEL_DEF_SLOPE_DURATION		1
10162306a36Sopenharmony_ci/* in terms of multiples of g's/LSB, based on range */
10262306a36Sopenharmony_ci#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD	1
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define BMC150_ACCEL_REG_XOUT_L		0x02
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define BMC150_ACCEL_MAX_STARTUP_TIME_MS	100
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/* Sleep Duration values */
10962306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_500_MICRO		0x05
11062306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_1_MS		0x06
11162306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_2_MS		0x07
11262306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_4_MS		0x08
11362306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_6_MS		0x09
11462306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_10_MS		0x0A
11562306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_25_MS		0x0B
11662306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_50_MS		0x0C
11762306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_100_MS		0x0D
11862306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_500_MS		0x0E
11962306a36Sopenharmony_ci#define BMC150_ACCEL_SLEEP_1_SEC		0x0F
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#define BMC150_ACCEL_REG_TEMP			0x08
12262306a36Sopenharmony_ci#define BMC150_ACCEL_TEMP_CENTER_VAL		23
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define BMC150_ACCEL_AXIS_TO_REG(axis)	(BMC150_ACCEL_REG_XOUT_L + (axis * 2))
12562306a36Sopenharmony_ci#define BMC150_AUTO_SUSPEND_DELAY_MS		2000
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define BMC150_ACCEL_REG_FIFO_STATUS		0x0E
12862306a36Sopenharmony_ci#define BMC150_ACCEL_REG_FIFO_CONFIG0		0x30
12962306a36Sopenharmony_ci#define BMC150_ACCEL_REG_FIFO_CONFIG1		0x3E
13062306a36Sopenharmony_ci#define BMC150_ACCEL_REG_FIFO_DATA		0x3F
13162306a36Sopenharmony_ci#define BMC150_ACCEL_FIFO_LENGTH		32
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cienum bmc150_accel_axis {
13462306a36Sopenharmony_ci	AXIS_X,
13562306a36Sopenharmony_ci	AXIS_Y,
13662306a36Sopenharmony_ci	AXIS_Z,
13762306a36Sopenharmony_ci	AXIS_MAX,
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cienum bmc150_power_modes {
14162306a36Sopenharmony_ci	BMC150_ACCEL_SLEEP_MODE_NORMAL,
14262306a36Sopenharmony_ci	BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND,
14362306a36Sopenharmony_ci	BMC150_ACCEL_SLEEP_MODE_LPM,
14462306a36Sopenharmony_ci	BMC150_ACCEL_SLEEP_MODE_SUSPEND = 0x04,
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistruct bmc150_scale_info {
14862306a36Sopenharmony_ci	int scale;
14962306a36Sopenharmony_ci	u8 reg_range;
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistruct bmc150_accel_chip_info {
15362306a36Sopenharmony_ci	const char *name;
15462306a36Sopenharmony_ci	u8 chip_id;
15562306a36Sopenharmony_ci	const struct iio_chan_spec *channels;
15662306a36Sopenharmony_ci	int num_channels;
15762306a36Sopenharmony_ci	const struct bmc150_scale_info scale_table[4];
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic const struct {
16162306a36Sopenharmony_ci	int val;
16262306a36Sopenharmony_ci	int val2;
16362306a36Sopenharmony_ci	u8 bw_bits;
16462306a36Sopenharmony_ci} bmc150_accel_samp_freq_table[] = { {15, 620000, 0x08},
16562306a36Sopenharmony_ci				     {31, 260000, 0x09},
16662306a36Sopenharmony_ci				     {62, 500000, 0x0A},
16762306a36Sopenharmony_ci				     {125, 0, 0x0B},
16862306a36Sopenharmony_ci				     {250, 0, 0x0C},
16962306a36Sopenharmony_ci				     {500, 0, 0x0D},
17062306a36Sopenharmony_ci				     {1000, 0, 0x0E},
17162306a36Sopenharmony_ci				     {2000, 0, 0x0F} };
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic __maybe_unused const struct {
17462306a36Sopenharmony_ci	int bw_bits;
17562306a36Sopenharmony_ci	int msec;
17662306a36Sopenharmony_ci} bmc150_accel_sample_upd_time[] = { {0x08, 64},
17762306a36Sopenharmony_ci				     {0x09, 32},
17862306a36Sopenharmony_ci				     {0x0A, 16},
17962306a36Sopenharmony_ci				     {0x0B, 8},
18062306a36Sopenharmony_ci				     {0x0C, 4},
18162306a36Sopenharmony_ci				     {0x0D, 2},
18262306a36Sopenharmony_ci				     {0x0E, 1},
18362306a36Sopenharmony_ci				     {0x0F, 1} };
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic const struct {
18662306a36Sopenharmony_ci	int sleep_dur;
18762306a36Sopenharmony_ci	u8 reg_value;
18862306a36Sopenharmony_ci} bmc150_accel_sleep_value_table[] = { {0, 0},
18962306a36Sopenharmony_ci				       {500, BMC150_ACCEL_SLEEP_500_MICRO},
19062306a36Sopenharmony_ci				       {1000, BMC150_ACCEL_SLEEP_1_MS},
19162306a36Sopenharmony_ci				       {2000, BMC150_ACCEL_SLEEP_2_MS},
19262306a36Sopenharmony_ci				       {4000, BMC150_ACCEL_SLEEP_4_MS},
19362306a36Sopenharmony_ci				       {6000, BMC150_ACCEL_SLEEP_6_MS},
19462306a36Sopenharmony_ci				       {10000, BMC150_ACCEL_SLEEP_10_MS},
19562306a36Sopenharmony_ci				       {25000, BMC150_ACCEL_SLEEP_25_MS},
19662306a36Sopenharmony_ci				       {50000, BMC150_ACCEL_SLEEP_50_MS},
19762306a36Sopenharmony_ci				       {100000, BMC150_ACCEL_SLEEP_100_MS},
19862306a36Sopenharmony_ci				       {500000, BMC150_ACCEL_SLEEP_500_MS},
19962306a36Sopenharmony_ci				       {1000000, BMC150_ACCEL_SLEEP_1_SEC} };
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ciconst struct regmap_config bmc150_regmap_conf = {
20262306a36Sopenharmony_ci	.reg_bits = 8,
20362306a36Sopenharmony_ci	.val_bits = 8,
20462306a36Sopenharmony_ci	.max_register = 0x3f,
20562306a36Sopenharmony_ci};
20662306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(bmc150_regmap_conf, IIO_BMC150);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic int bmc150_accel_set_mode(struct bmc150_accel_data *data,
20962306a36Sopenharmony_ci				 enum bmc150_power_modes mode,
21062306a36Sopenharmony_ci				 int dur_us)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
21362306a36Sopenharmony_ci	int i;
21462306a36Sopenharmony_ci	int ret;
21562306a36Sopenharmony_ci	u8 lpw_bits;
21662306a36Sopenharmony_ci	int dur_val = -1;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (dur_us > 0) {
21962306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(bmc150_accel_sleep_value_table);
22062306a36Sopenharmony_ci									 ++i) {
22162306a36Sopenharmony_ci			if (bmc150_accel_sleep_value_table[i].sleep_dur ==
22262306a36Sopenharmony_ci									dur_us)
22362306a36Sopenharmony_ci				dur_val =
22462306a36Sopenharmony_ci				bmc150_accel_sleep_value_table[i].reg_value;
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci	} else {
22762306a36Sopenharmony_ci		dur_val = 0;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (dur_val < 0)
23162306a36Sopenharmony_ci		return -EINVAL;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT;
23462306a36Sopenharmony_ci	lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	dev_dbg(dev, "Set Mode bits %x\n", lpw_bits);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_LPW, lpw_bits);
23962306a36Sopenharmony_ci	if (ret < 0) {
24062306a36Sopenharmony_ci		dev_err(dev, "Error writing reg_pmu_lpw\n");
24162306a36Sopenharmony_ci		return ret;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
24862306a36Sopenharmony_ci			       int val2)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	int i;
25162306a36Sopenharmony_ci	int ret;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) {
25462306a36Sopenharmony_ci		if (bmc150_accel_samp_freq_table[i].val == val &&
25562306a36Sopenharmony_ci		    bmc150_accel_samp_freq_table[i].val2 == val2) {
25662306a36Sopenharmony_ci			ret = regmap_write(data->regmap,
25762306a36Sopenharmony_ci				BMC150_ACCEL_REG_PMU_BW,
25862306a36Sopenharmony_ci				bmc150_accel_samp_freq_table[i].bw_bits);
25962306a36Sopenharmony_ci			if (ret < 0)
26062306a36Sopenharmony_ci				return ret;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci			data->bw_bits =
26362306a36Sopenharmony_ci				bmc150_accel_samp_freq_table[i].bw_bits;
26462306a36Sopenharmony_ci			return 0;
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return -EINVAL;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int bmc150_accel_update_slope(struct bmc150_accel_data *data)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
27462306a36Sopenharmony_ci	int ret;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_6,
27762306a36Sopenharmony_ci					data->slope_thres);
27862306a36Sopenharmony_ci	if (ret < 0) {
27962306a36Sopenharmony_ci		dev_err(dev, "Error writing reg_int_6\n");
28062306a36Sopenharmony_ci		return ret;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, BMC150_ACCEL_REG_INT_5,
28462306a36Sopenharmony_ci				 BMC150_ACCEL_SLOPE_DUR_MASK, data->slope_dur);
28562306a36Sopenharmony_ci	if (ret < 0) {
28662306a36Sopenharmony_ci		dev_err(dev, "Error updating reg_int_5\n");
28762306a36Sopenharmony_ci		return ret;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	dev_dbg(dev, "%x %x\n", data->slope_thres, data->slope_dur);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return ret;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t,
29662306a36Sopenharmony_ci					 bool state)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	if (state)
29962306a36Sopenharmony_ci		return bmc150_accel_update_slope(t->data);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return 0;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val,
30562306a36Sopenharmony_ci			       int *val2)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	int i;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) {
31062306a36Sopenharmony_ci		if (bmc150_accel_samp_freq_table[i].bw_bits == data->bw_bits) {
31162306a36Sopenharmony_ci			*val = bmc150_accel_samp_freq_table[i].val;
31262306a36Sopenharmony_ci			*val2 = bmc150_accel_samp_freq_table[i].val2;
31362306a36Sopenharmony_ci			return IIO_VAL_INT_PLUS_MICRO;
31462306a36Sopenharmony_ci		}
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return -EINVAL;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci#ifdef CONFIG_PM
32162306a36Sopenharmony_cistatic int bmc150_accel_get_startup_times(struct bmc150_accel_data *data)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	int i;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bmc150_accel_sample_upd_time); ++i) {
32662306a36Sopenharmony_ci		if (bmc150_accel_sample_upd_time[i].bw_bits == data->bw_bits)
32762306a36Sopenharmony_ci			return bmc150_accel_sample_upd_time[i].msec;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return BMC150_ACCEL_MAX_STARTUP_TIME_MS;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
33662306a36Sopenharmony_ci	int ret;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (on) {
33962306a36Sopenharmony_ci		ret = pm_runtime_resume_and_get(dev);
34062306a36Sopenharmony_ci	} else {
34162306a36Sopenharmony_ci		pm_runtime_mark_last_busy(dev);
34262306a36Sopenharmony_ci		ret = pm_runtime_put_autosuspend(dev);
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (ret < 0) {
34662306a36Sopenharmony_ci		dev_err(dev,
34762306a36Sopenharmony_ci			"Failed: %s for %d\n", __func__, on);
34862306a36Sopenharmony_ci		return ret;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return 0;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci#else
35462306a36Sopenharmony_cistatic int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	return 0;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci#endif
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci#ifdef CONFIG_ACPI
36162306a36Sopenharmony_ci/*
36262306a36Sopenharmony_ci * Support for getting accelerometer information from BOSC0200 ACPI nodes.
36362306a36Sopenharmony_ci *
36462306a36Sopenharmony_ci * There are 2 variants of the BOSC0200 ACPI node. Some 2-in-1s with 360 degree
36562306a36Sopenharmony_ci * hinges declare 2 I2C ACPI-resources for 2 accelerometers, 1 in the display
36662306a36Sopenharmony_ci * and 1 in the base of the 2-in-1. On these 2-in-1s the ROMS ACPI object
36762306a36Sopenharmony_ci * contains the mount-matrix for the sensor in the display and ROMK contains
36862306a36Sopenharmony_ci * the mount-matrix for the sensor in the base. On devices using a single
36962306a36Sopenharmony_ci * sensor there is a ROTM ACPI object which contains the mount-matrix.
37062306a36Sopenharmony_ci *
37162306a36Sopenharmony_ci * Here is an incomplete list of devices known to use 1 of these setups:
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * Yoga devices with 2 accelerometers using ROMS + ROMK for the mount-matrices:
37462306a36Sopenharmony_ci * Lenovo Thinkpad Yoga 11e 3th gen
37562306a36Sopenharmony_ci * Lenovo Thinkpad Yoga 11e 4th gen
37662306a36Sopenharmony_ci *
37762306a36Sopenharmony_ci * Tablets using a single accelerometer using ROTM for the mount-matrix:
37862306a36Sopenharmony_ci * Chuwi Hi8 Pro (CWI513)
37962306a36Sopenharmony_ci * Chuwi Vi8 Plus (CWI519)
38062306a36Sopenharmony_ci * Chuwi Hi13
38162306a36Sopenharmony_ci * Irbis TW90
38262306a36Sopenharmony_ci * Jumper EZpad mini 3
38362306a36Sopenharmony_ci * Onda V80 plus
38462306a36Sopenharmony_ci * Predia Basic Tablet
38562306a36Sopenharmony_ci */
38662306a36Sopenharmony_cistatic bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev,
38762306a36Sopenharmony_ci						   struct iio_mount_matrix *orientation)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
39062306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
39162306a36Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(dev);
39262306a36Sopenharmony_ci	char *name, *alt_name, *label, *str;
39362306a36Sopenharmony_ci	union acpi_object *obj, *elements;
39462306a36Sopenharmony_ci	acpi_status status;
39562306a36Sopenharmony_ci	int i, j, val[3];
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) {
39862306a36Sopenharmony_ci		alt_name = "ROMK";
39962306a36Sopenharmony_ci		label = "accel-base";
40062306a36Sopenharmony_ci	} else {
40162306a36Sopenharmony_ci		alt_name = "ROMS";
40262306a36Sopenharmony_ci		label = "accel-display";
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (acpi_has_method(adev->handle, "ROTM")) {
40662306a36Sopenharmony_ci		name = "ROTM";
40762306a36Sopenharmony_ci	} else if (acpi_has_method(adev->handle, alt_name)) {
40862306a36Sopenharmony_ci		name = alt_name;
40962306a36Sopenharmony_ci		indio_dev->label = label;
41062306a36Sopenharmony_ci	} else {
41162306a36Sopenharmony_ci		return false;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	status = acpi_evaluate_object(adev->handle, name, NULL, &buffer);
41562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
41662306a36Sopenharmony_ci		dev_warn(dev, "Failed to get ACPI mount matrix: %d\n", status);
41762306a36Sopenharmony_ci		return false;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	obj = buffer.pointer;
42162306a36Sopenharmony_ci	if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3)
42262306a36Sopenharmony_ci		goto unknown_format;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	elements = obj->package.elements;
42562306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
42662306a36Sopenharmony_ci		if (elements[i].type != ACPI_TYPE_STRING)
42762306a36Sopenharmony_ci			goto unknown_format;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		str = elements[i].string.pointer;
43062306a36Sopenharmony_ci		if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3)
43162306a36Sopenharmony_ci			goto unknown_format;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		for (j = 0; j < 3; j++) {
43462306a36Sopenharmony_ci			switch (val[j]) {
43562306a36Sopenharmony_ci			case -1: str = "-1"; break;
43662306a36Sopenharmony_ci			case 0:  str = "0";  break;
43762306a36Sopenharmony_ci			case 1:  str = "1";  break;
43862306a36Sopenharmony_ci			default: goto unknown_format;
43962306a36Sopenharmony_ci			}
44062306a36Sopenharmony_ci			orientation->rotation[i * 3 + j] = str;
44162306a36Sopenharmony_ci		}
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	kfree(buffer.pointer);
44562306a36Sopenharmony_ci	return true;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ciunknown_format:
44862306a36Sopenharmony_ci	dev_warn(dev, "Unknown ACPI mount matrix format, ignoring\n");
44962306a36Sopenharmony_ci	kfree(buffer.pointer);
45062306a36Sopenharmony_ci	return false;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic bool bmc150_apply_dual250e_acpi_orientation(struct device *dev,
45462306a36Sopenharmony_ci						   struct iio_mount_matrix *orientation)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (strcmp(dev_name(dev), "i2c-DUAL250E:base") == 0)
45962306a36Sopenharmony_ci		indio_dev->label = "accel-base";
46062306a36Sopenharmony_ci	else
46162306a36Sopenharmony_ci		indio_dev->label = "accel-display";
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return false; /* DUAL250E fwnodes have no mount matrix info */
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic bool bmc150_apply_acpi_orientation(struct device *dev,
46762306a36Sopenharmony_ci					  struct iio_mount_matrix *orientation)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(dev);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (adev && acpi_dev_hid_uid_match(adev, "BOSC0200", NULL))
47262306a36Sopenharmony_ci		return bmc150_apply_bosc0200_acpi_orientation(dev, orientation);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (adev && acpi_dev_hid_uid_match(adev, "DUAL250E", NULL))
47562306a36Sopenharmony_ci		return bmc150_apply_dual250e_acpi_orientation(dev, orientation);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return false;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci#else
48062306a36Sopenharmony_cistatic bool bmc150_apply_acpi_orientation(struct device *dev,
48162306a36Sopenharmony_ci					  struct iio_mount_matrix *orientation)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	return false;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci#endif
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistruct bmc150_accel_interrupt_info {
48862306a36Sopenharmony_ci	u8 map_reg;
48962306a36Sopenharmony_ci	u8 map_bitmask;
49062306a36Sopenharmony_ci	u8 en_reg;
49162306a36Sopenharmony_ci	u8 en_bitmask;
49262306a36Sopenharmony_ci};
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic const struct bmc150_accel_interrupt_info
49562306a36Sopenharmony_cibmc150_accel_interrupts_int1[BMC150_ACCEL_INTERRUPTS] = {
49662306a36Sopenharmony_ci	{ /* data ready interrupt */
49762306a36Sopenharmony_ci		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
49862306a36Sopenharmony_ci		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA,
49962306a36Sopenharmony_ci		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
50062306a36Sopenharmony_ci		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
50162306a36Sopenharmony_ci	},
50262306a36Sopenharmony_ci	{  /* motion interrupt */
50362306a36Sopenharmony_ci		.map_reg = BMC150_ACCEL_REG_INT_MAP_0,
50462306a36Sopenharmony_ci		.map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE,
50562306a36Sopenharmony_ci		.en_reg = BMC150_ACCEL_REG_INT_EN_0,
50662306a36Sopenharmony_ci		.en_bitmask =  BMC150_ACCEL_INT_EN_BIT_SLP_X |
50762306a36Sopenharmony_ci			BMC150_ACCEL_INT_EN_BIT_SLP_Y |
50862306a36Sopenharmony_ci			BMC150_ACCEL_INT_EN_BIT_SLP_Z
50962306a36Sopenharmony_ci	},
51062306a36Sopenharmony_ci	{ /* fifo watermark interrupt */
51162306a36Sopenharmony_ci		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
51262306a36Sopenharmony_ci		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM,
51362306a36Sopenharmony_ci		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
51462306a36Sopenharmony_ci		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
51562306a36Sopenharmony_ci	},
51662306a36Sopenharmony_ci};
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic const struct bmc150_accel_interrupt_info
51962306a36Sopenharmony_cibmc150_accel_interrupts_int2[BMC150_ACCEL_INTERRUPTS] = {
52062306a36Sopenharmony_ci	{ /* data ready interrupt */
52162306a36Sopenharmony_ci		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
52262306a36Sopenharmony_ci		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA,
52362306a36Sopenharmony_ci		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
52462306a36Sopenharmony_ci		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
52562306a36Sopenharmony_ci	},
52662306a36Sopenharmony_ci	{  /* motion interrupt */
52762306a36Sopenharmony_ci		.map_reg = BMC150_ACCEL_REG_INT_MAP_2,
52862306a36Sopenharmony_ci		.map_bitmask = BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE,
52962306a36Sopenharmony_ci		.en_reg = BMC150_ACCEL_REG_INT_EN_0,
53062306a36Sopenharmony_ci		.en_bitmask =  BMC150_ACCEL_INT_EN_BIT_SLP_X |
53162306a36Sopenharmony_ci			BMC150_ACCEL_INT_EN_BIT_SLP_Y |
53262306a36Sopenharmony_ci			BMC150_ACCEL_INT_EN_BIT_SLP_Z
53362306a36Sopenharmony_ci	},
53462306a36Sopenharmony_ci	{ /* fifo watermark interrupt */
53562306a36Sopenharmony_ci		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
53662306a36Sopenharmony_ci		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM,
53762306a36Sopenharmony_ci		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
53862306a36Sopenharmony_ci		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
53962306a36Sopenharmony_ci	},
54062306a36Sopenharmony_ci};
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
54362306a36Sopenharmony_ci					  struct bmc150_accel_data *data, int irq)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	const struct bmc150_accel_interrupt_info *irq_info = NULL;
54662306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
54762306a36Sopenharmony_ci	int i;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/*
55062306a36Sopenharmony_ci	 * For now we map all interrupts to the same output pin.
55162306a36Sopenharmony_ci	 * However, some boards may have just INT2 (and not INT1) connected,
55262306a36Sopenharmony_ci	 * so we try to detect which IRQ it is based on the interrupt-names.
55362306a36Sopenharmony_ci	 * Without interrupt-names, we assume the irq belongs to INT1.
55462306a36Sopenharmony_ci	 */
55562306a36Sopenharmony_ci	irq_info = bmc150_accel_interrupts_int1;
55662306a36Sopenharmony_ci	if (data->type == BOSCH_BMC156 ||
55762306a36Sopenharmony_ci	    irq == of_irq_get_byname(dev->of_node, "INT2"))
55862306a36Sopenharmony_ci		irq_info = bmc150_accel_interrupts_int2;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++)
56162306a36Sopenharmony_ci		data->interrupts[i].info = &irq_info[i];
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
56562306a36Sopenharmony_ci				      bool state)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
56862306a36Sopenharmony_ci	struct bmc150_accel_interrupt *intr = &data->interrupts[i];
56962306a36Sopenharmony_ci	const struct bmc150_accel_interrupt_info *info = intr->info;
57062306a36Sopenharmony_ci	int ret;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	if (state) {
57362306a36Sopenharmony_ci		if (atomic_inc_return(&intr->users) > 1)
57462306a36Sopenharmony_ci			return 0;
57562306a36Sopenharmony_ci	} else {
57662306a36Sopenharmony_ci		if (atomic_dec_return(&intr->users) > 0)
57762306a36Sopenharmony_ci			return 0;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/*
58162306a36Sopenharmony_ci	 * We will expect the enable and disable to do operation in reverse
58262306a36Sopenharmony_ci	 * order. This will happen here anyway, as our resume operation uses
58362306a36Sopenharmony_ci	 * sync mode runtime pm calls. The suspend operation will be delayed
58462306a36Sopenharmony_ci	 * by autosuspend delay.
58562306a36Sopenharmony_ci	 * So the disable operation will still happen in reverse order of
58662306a36Sopenharmony_ci	 * enable operation. When runtime pm is disabled the mode is always on,
58762306a36Sopenharmony_ci	 * so sequence doesn't matter.
58862306a36Sopenharmony_ci	 */
58962306a36Sopenharmony_ci	ret = bmc150_accel_set_power_state(data, state);
59062306a36Sopenharmony_ci	if (ret < 0)
59162306a36Sopenharmony_ci		return ret;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/* map the interrupt to the appropriate pins */
59462306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, info->map_reg, info->map_bitmask,
59562306a36Sopenharmony_ci				 (state ? info->map_bitmask : 0));
59662306a36Sopenharmony_ci	if (ret < 0) {
59762306a36Sopenharmony_ci		dev_err(dev, "Error updating reg_int_map\n");
59862306a36Sopenharmony_ci		goto out_fix_power_state;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* enable/disable the interrupt */
60262306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, info->en_reg, info->en_bitmask,
60362306a36Sopenharmony_ci				 (state ? info->en_bitmask : 0));
60462306a36Sopenharmony_ci	if (ret < 0) {
60562306a36Sopenharmony_ci		dev_err(dev, "Error updating reg_int_en\n");
60662306a36Sopenharmony_ci		goto out_fix_power_state;
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	return 0;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ciout_fix_power_state:
61262306a36Sopenharmony_ci	bmc150_accel_set_power_state(data, false);
61362306a36Sopenharmony_ci	return ret;
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
61962306a36Sopenharmony_ci	int ret, i;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) {
62262306a36Sopenharmony_ci		if (data->chip_info->scale_table[i].scale == val) {
62362306a36Sopenharmony_ci			ret = regmap_write(data->regmap,
62462306a36Sopenharmony_ci				     BMC150_ACCEL_REG_PMU_RANGE,
62562306a36Sopenharmony_ci				     data->chip_info->scale_table[i].reg_range);
62662306a36Sopenharmony_ci			if (ret < 0) {
62762306a36Sopenharmony_ci				dev_err(dev, "Error writing pmu_range\n");
62862306a36Sopenharmony_ci				return ret;
62962306a36Sopenharmony_ci			}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci			data->range = data->chip_info->scale_table[i].reg_range;
63262306a36Sopenharmony_ci			return 0;
63362306a36Sopenharmony_ci		}
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	return -EINVAL;
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
64262306a36Sopenharmony_ci	int ret;
64362306a36Sopenharmony_ci	unsigned int value;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	mutex_lock(&data->mutex);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	ret = regmap_read(data->regmap, BMC150_ACCEL_REG_TEMP, &value);
64862306a36Sopenharmony_ci	if (ret < 0) {
64962306a36Sopenharmony_ci		dev_err(dev, "Error reading reg_temp\n");
65062306a36Sopenharmony_ci		mutex_unlock(&data->mutex);
65162306a36Sopenharmony_ci		return ret;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci	*val = sign_extend32(value, 7);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	return IIO_VAL_INT;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic int bmc150_accel_get_axis(struct bmc150_accel_data *data,
66162306a36Sopenharmony_ci				 struct iio_chan_spec const *chan,
66262306a36Sopenharmony_ci				 int *val)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
66562306a36Sopenharmony_ci	int ret;
66662306a36Sopenharmony_ci	int axis = chan->scan_index;
66762306a36Sopenharmony_ci	__le16 raw_val;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	mutex_lock(&data->mutex);
67062306a36Sopenharmony_ci	ret = bmc150_accel_set_power_state(data, true);
67162306a36Sopenharmony_ci	if (ret < 0) {
67262306a36Sopenharmony_ci		mutex_unlock(&data->mutex);
67362306a36Sopenharmony_ci		return ret;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis),
67762306a36Sopenharmony_ci			       &raw_val, sizeof(raw_val));
67862306a36Sopenharmony_ci	if (ret < 0) {
67962306a36Sopenharmony_ci		dev_err(dev, "Error reading axis %d\n", axis);
68062306a36Sopenharmony_ci		bmc150_accel_set_power_state(data, false);
68162306a36Sopenharmony_ci		mutex_unlock(&data->mutex);
68262306a36Sopenharmony_ci		return ret;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci	*val = sign_extend32(le16_to_cpu(raw_val) >> chan->scan_type.shift,
68562306a36Sopenharmony_ci			     chan->scan_type.realbits - 1);
68662306a36Sopenharmony_ci	ret = bmc150_accel_set_power_state(data, false);
68762306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
68862306a36Sopenharmony_ci	if (ret < 0)
68962306a36Sopenharmony_ci		return ret;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	return IIO_VAL_INT;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic int bmc150_accel_read_raw(struct iio_dev *indio_dev,
69562306a36Sopenharmony_ci				 struct iio_chan_spec const *chan,
69662306a36Sopenharmony_ci				 int *val, int *val2, long mask)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
69962306a36Sopenharmony_ci	int ret;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	switch (mask) {
70262306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
70362306a36Sopenharmony_ci		switch (chan->type) {
70462306a36Sopenharmony_ci		case IIO_TEMP:
70562306a36Sopenharmony_ci			return bmc150_accel_get_temp(data, val);
70662306a36Sopenharmony_ci		case IIO_ACCEL:
70762306a36Sopenharmony_ci			if (iio_buffer_enabled(indio_dev))
70862306a36Sopenharmony_ci				return -EBUSY;
70962306a36Sopenharmony_ci			else
71062306a36Sopenharmony_ci				return bmc150_accel_get_axis(data, chan, val);
71162306a36Sopenharmony_ci		default:
71262306a36Sopenharmony_ci			return -EINVAL;
71362306a36Sopenharmony_ci		}
71462306a36Sopenharmony_ci	case IIO_CHAN_INFO_OFFSET:
71562306a36Sopenharmony_ci		if (chan->type == IIO_TEMP) {
71662306a36Sopenharmony_ci			*val = BMC150_ACCEL_TEMP_CENTER_VAL;
71762306a36Sopenharmony_ci			return IIO_VAL_INT;
71862306a36Sopenharmony_ci		} else {
71962306a36Sopenharmony_ci			return -EINVAL;
72062306a36Sopenharmony_ci		}
72162306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
72262306a36Sopenharmony_ci		*val = 0;
72362306a36Sopenharmony_ci		switch (chan->type) {
72462306a36Sopenharmony_ci		case IIO_TEMP:
72562306a36Sopenharmony_ci			*val2 = 500000;
72662306a36Sopenharmony_ci			return IIO_VAL_INT_PLUS_MICRO;
72762306a36Sopenharmony_ci		case IIO_ACCEL:
72862306a36Sopenharmony_ci		{
72962306a36Sopenharmony_ci			int i;
73062306a36Sopenharmony_ci			const struct bmc150_scale_info *si;
73162306a36Sopenharmony_ci			int st_size = ARRAY_SIZE(data->chip_info->scale_table);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci			for (i = 0; i < st_size; ++i) {
73462306a36Sopenharmony_ci				si = &data->chip_info->scale_table[i];
73562306a36Sopenharmony_ci				if (si->reg_range == data->range) {
73662306a36Sopenharmony_ci					*val2 = si->scale;
73762306a36Sopenharmony_ci					return IIO_VAL_INT_PLUS_MICRO;
73862306a36Sopenharmony_ci				}
73962306a36Sopenharmony_ci			}
74062306a36Sopenharmony_ci			return -EINVAL;
74162306a36Sopenharmony_ci		}
74262306a36Sopenharmony_ci		default:
74362306a36Sopenharmony_ci			return -EINVAL;
74462306a36Sopenharmony_ci		}
74562306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
74662306a36Sopenharmony_ci		mutex_lock(&data->mutex);
74762306a36Sopenharmony_ci		ret = bmc150_accel_get_bw(data, val, val2);
74862306a36Sopenharmony_ci		mutex_unlock(&data->mutex);
74962306a36Sopenharmony_ci		return ret;
75062306a36Sopenharmony_ci	default:
75162306a36Sopenharmony_ci		return -EINVAL;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic int bmc150_accel_write_raw(struct iio_dev *indio_dev,
75662306a36Sopenharmony_ci				  struct iio_chan_spec const *chan,
75762306a36Sopenharmony_ci				  int val, int val2, long mask)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
76062306a36Sopenharmony_ci	int ret;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	switch (mask) {
76362306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
76462306a36Sopenharmony_ci		mutex_lock(&data->mutex);
76562306a36Sopenharmony_ci		ret = bmc150_accel_set_bw(data, val, val2);
76662306a36Sopenharmony_ci		mutex_unlock(&data->mutex);
76762306a36Sopenharmony_ci		break;
76862306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
76962306a36Sopenharmony_ci		if (val)
77062306a36Sopenharmony_ci			return -EINVAL;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		mutex_lock(&data->mutex);
77362306a36Sopenharmony_ci		ret = bmc150_accel_set_scale(data, val2);
77462306a36Sopenharmony_ci		mutex_unlock(&data->mutex);
77562306a36Sopenharmony_ci		return ret;
77662306a36Sopenharmony_ci	default:
77762306a36Sopenharmony_ci		ret = -EINVAL;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	return ret;
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic int bmc150_accel_read_event(struct iio_dev *indio_dev,
78462306a36Sopenharmony_ci				   const struct iio_chan_spec *chan,
78562306a36Sopenharmony_ci				   enum iio_event_type type,
78662306a36Sopenharmony_ci				   enum iio_event_direction dir,
78762306a36Sopenharmony_ci				   enum iio_event_info info,
78862306a36Sopenharmony_ci				   int *val, int *val2)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	*val2 = 0;
79362306a36Sopenharmony_ci	switch (info) {
79462306a36Sopenharmony_ci	case IIO_EV_INFO_VALUE:
79562306a36Sopenharmony_ci		*val = data->slope_thres;
79662306a36Sopenharmony_ci		break;
79762306a36Sopenharmony_ci	case IIO_EV_INFO_PERIOD:
79862306a36Sopenharmony_ci		*val = data->slope_dur;
79962306a36Sopenharmony_ci		break;
80062306a36Sopenharmony_ci	default:
80162306a36Sopenharmony_ci		return -EINVAL;
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return IIO_VAL_INT;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic int bmc150_accel_write_event(struct iio_dev *indio_dev,
80862306a36Sopenharmony_ci				    const struct iio_chan_spec *chan,
80962306a36Sopenharmony_ci				    enum iio_event_type type,
81062306a36Sopenharmony_ci				    enum iio_event_direction dir,
81162306a36Sopenharmony_ci				    enum iio_event_info info,
81262306a36Sopenharmony_ci				    int val, int val2)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	if (data->ev_enable_state)
81762306a36Sopenharmony_ci		return -EBUSY;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	switch (info) {
82062306a36Sopenharmony_ci	case IIO_EV_INFO_VALUE:
82162306a36Sopenharmony_ci		data->slope_thres = val & BMC150_ACCEL_SLOPE_THRES_MASK;
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci	case IIO_EV_INFO_PERIOD:
82462306a36Sopenharmony_ci		data->slope_dur = val & BMC150_ACCEL_SLOPE_DUR_MASK;
82562306a36Sopenharmony_ci		break;
82662306a36Sopenharmony_ci	default:
82762306a36Sopenharmony_ci		return -EINVAL;
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return 0;
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cistatic int bmc150_accel_read_event_config(struct iio_dev *indio_dev,
83462306a36Sopenharmony_ci					  const struct iio_chan_spec *chan,
83562306a36Sopenharmony_ci					  enum iio_event_type type,
83662306a36Sopenharmony_ci					  enum iio_event_direction dir)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	return data->ev_enable_state;
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
84462306a36Sopenharmony_ci					   const struct iio_chan_spec *chan,
84562306a36Sopenharmony_ci					   enum iio_event_type type,
84662306a36Sopenharmony_ci					   enum iio_event_direction dir,
84762306a36Sopenharmony_ci					   int state)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
85062306a36Sopenharmony_ci	int ret;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	if (state == data->ev_enable_state)
85362306a36Sopenharmony_ci		return 0;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	mutex_lock(&data->mutex);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_ANY_MOTION,
85862306a36Sopenharmony_ci					 state);
85962306a36Sopenharmony_ci	if (ret < 0) {
86062306a36Sopenharmony_ci		mutex_unlock(&data->mutex);
86162306a36Sopenharmony_ci		return ret;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	data->ev_enable_state = state;
86562306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	return 0;
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
87162306a36Sopenharmony_ci					 struct iio_trigger *trig)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
87462306a36Sopenharmony_ci	int i;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
87762306a36Sopenharmony_ci		if (data->triggers[i].indio_trig == trig)
87862306a36Sopenharmony_ci			return 0;
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	return -EINVAL;
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cistatic ssize_t bmc150_accel_get_fifo_watermark(struct device *dev,
88562306a36Sopenharmony_ci					       struct device_attribute *attr,
88662306a36Sopenharmony_ci					       char *buf)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
88962306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
89062306a36Sopenharmony_ci	int wm;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	mutex_lock(&data->mutex);
89362306a36Sopenharmony_ci	wm = data->watermark;
89462306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	return sprintf(buf, "%d\n", wm);
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_cistatic ssize_t bmc150_accel_get_fifo_state(struct device *dev,
90062306a36Sopenharmony_ci					   struct device_attribute *attr,
90162306a36Sopenharmony_ci					   char *buf)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
90462306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
90562306a36Sopenharmony_ci	bool state;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	mutex_lock(&data->mutex);
90862306a36Sopenharmony_ci	state = data->fifo_mode;
90962306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	return sprintf(buf, "%d\n", state);
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic const struct iio_mount_matrix *
91562306a36Sopenharmony_cibmc150_accel_get_mount_matrix(const struct iio_dev *indio_dev,
91662306a36Sopenharmony_ci				const struct iio_chan_spec *chan)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	return &data->orientation;
92162306a36Sopenharmony_ci}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_cistatic const struct iio_chan_spec_ext_info bmc150_accel_ext_info[] = {
92462306a36Sopenharmony_ci	IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_accel_get_mount_matrix),
92562306a36Sopenharmony_ci	{ }
92662306a36Sopenharmony_ci};
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ciIIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
92962306a36Sopenharmony_ciIIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
93062306a36Sopenharmony_ci			     __stringify(BMC150_ACCEL_FIFO_LENGTH));
93162306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO,
93262306a36Sopenharmony_ci		       bmc150_accel_get_fifo_state, NULL, 0);
93362306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO,
93462306a36Sopenharmony_ci		       bmc150_accel_get_fifo_watermark, NULL, 0);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_cistatic const struct iio_dev_attr *bmc150_accel_fifo_attributes[] = {
93762306a36Sopenharmony_ci	&iio_dev_attr_hwfifo_watermark_min,
93862306a36Sopenharmony_ci	&iio_dev_attr_hwfifo_watermark_max,
93962306a36Sopenharmony_ci	&iio_dev_attr_hwfifo_watermark,
94062306a36Sopenharmony_ci	&iio_dev_attr_hwfifo_enabled,
94162306a36Sopenharmony_ci	NULL,
94262306a36Sopenharmony_ci};
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	if (val > BMC150_ACCEL_FIFO_LENGTH)
94962306a36Sopenharmony_ci		val = BMC150_ACCEL_FIFO_LENGTH;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	mutex_lock(&data->mutex);
95262306a36Sopenharmony_ci	data->watermark = val;
95362306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	return 0;
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci/*
95962306a36Sopenharmony_ci * We must read at least one full frame in one burst, otherwise the rest of the
96062306a36Sopenharmony_ci * frame data is discarded.
96162306a36Sopenharmony_ci */
96262306a36Sopenharmony_cistatic int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data,
96362306a36Sopenharmony_ci				      char *buffer, int samples)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
96662306a36Sopenharmony_ci	int sample_length = 3 * 2;
96762306a36Sopenharmony_ci	int ret;
96862306a36Sopenharmony_ci	int total_length = samples * sample_length;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA,
97162306a36Sopenharmony_ci			      buffer, total_length);
97262306a36Sopenharmony_ci	if (ret)
97362306a36Sopenharmony_ci		dev_err(dev,
97462306a36Sopenharmony_ci			"Error transferring data from fifo: %d\n", ret);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	return ret;
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cistatic int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
98062306a36Sopenharmony_ci				     unsigned samples, bool irq)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
98362306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
98462306a36Sopenharmony_ci	int ret, i;
98562306a36Sopenharmony_ci	u8 count;
98662306a36Sopenharmony_ci	u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
98762306a36Sopenharmony_ci	int64_t tstamp;
98862306a36Sopenharmony_ci	uint64_t sample_period;
98962306a36Sopenharmony_ci	unsigned int val;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	ret = regmap_read(data->regmap, BMC150_ACCEL_REG_FIFO_STATUS, &val);
99262306a36Sopenharmony_ci	if (ret < 0) {
99362306a36Sopenharmony_ci		dev_err(dev, "Error reading reg_fifo_status\n");
99462306a36Sopenharmony_ci		return ret;
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	count = val & 0x7F;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	if (!count)
100062306a36Sopenharmony_ci		return 0;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	/*
100362306a36Sopenharmony_ci	 * If we getting called from IRQ handler we know the stored timestamp is
100462306a36Sopenharmony_ci	 * fairly accurate for the last stored sample. Otherwise, if we are
100562306a36Sopenharmony_ci	 * called as a result of a read operation from userspace and hence
100662306a36Sopenharmony_ci	 * before the watermark interrupt was triggered, take a timestamp
100762306a36Sopenharmony_ci	 * now. We can fall anywhere in between two samples so the error in this
100862306a36Sopenharmony_ci	 * case is at most one sample period.
100962306a36Sopenharmony_ci	 */
101062306a36Sopenharmony_ci	if (!irq) {
101162306a36Sopenharmony_ci		data->old_timestamp = data->timestamp;
101262306a36Sopenharmony_ci		data->timestamp = iio_get_time_ns(indio_dev);
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	/*
101662306a36Sopenharmony_ci	 * Approximate timestamps for each of the sample based on the sampling
101762306a36Sopenharmony_ci	 * frequency, timestamp for last sample and number of samples.
101862306a36Sopenharmony_ci	 *
101962306a36Sopenharmony_ci	 * Note that we can't use the current bandwidth settings to compute the
102062306a36Sopenharmony_ci	 * sample period because the sample rate varies with the device
102162306a36Sopenharmony_ci	 * (e.g. between 31.70ms to 32.20ms for a bandwidth of 15.63HZ). That
102262306a36Sopenharmony_ci	 * small variation adds when we store a large number of samples and
102362306a36Sopenharmony_ci	 * creates significant jitter between the last and first samples in
102462306a36Sopenharmony_ci	 * different batches (e.g. 32ms vs 21ms).
102562306a36Sopenharmony_ci	 *
102662306a36Sopenharmony_ci	 * To avoid this issue we compute the actual sample period ourselves
102762306a36Sopenharmony_ci	 * based on the timestamp delta between the last two flush operations.
102862306a36Sopenharmony_ci	 */
102962306a36Sopenharmony_ci	sample_period = (data->timestamp - data->old_timestamp);
103062306a36Sopenharmony_ci	do_div(sample_period, count);
103162306a36Sopenharmony_ci	tstamp = data->timestamp - (count - 1) * sample_period;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	if (samples && count > samples)
103462306a36Sopenharmony_ci		count = samples;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count);
103762306a36Sopenharmony_ci	if (ret)
103862306a36Sopenharmony_ci		return ret;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	/*
104162306a36Sopenharmony_ci	 * Ideally we want the IIO core to handle the demux when running in fifo
104262306a36Sopenharmony_ci	 * mode but not when running in triggered buffer mode. Unfortunately
104362306a36Sopenharmony_ci	 * this does not seem to be possible, so stick with driver demux for
104462306a36Sopenharmony_ci	 * now.
104562306a36Sopenharmony_ci	 */
104662306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
104762306a36Sopenharmony_ci		int j, bit;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci		j = 0;
105062306a36Sopenharmony_ci		for_each_set_bit(bit, indio_dev->active_scan_mask,
105162306a36Sopenharmony_ci				 indio_dev->masklength)
105262306a36Sopenharmony_ci			memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
105362306a36Sopenharmony_ci			       sizeof(data->scan.channels[0]));
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
105662306a36Sopenharmony_ci						   tstamp);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci		tstamp += sample_period;
105962306a36Sopenharmony_ci	}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	return count;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic int bmc150_accel_fifo_flush(struct iio_dev *indio_dev, unsigned samples)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
106762306a36Sopenharmony_ci	int ret;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	mutex_lock(&data->mutex);
107062306a36Sopenharmony_ci	ret = __bmc150_accel_fifo_flush(indio_dev, samples, false);
107162306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	return ret;
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_cistatic IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
107762306a36Sopenharmony_ci		"15.620000 31.260000 62.50000 125 250 500 1000 2000");
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic struct attribute *bmc150_accel_attributes[] = {
108062306a36Sopenharmony_ci	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
108162306a36Sopenharmony_ci	NULL,
108262306a36Sopenharmony_ci};
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic const struct attribute_group bmc150_accel_attrs_group = {
108562306a36Sopenharmony_ci	.attrs = bmc150_accel_attributes,
108662306a36Sopenharmony_ci};
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic const struct iio_event_spec bmc150_accel_event = {
108962306a36Sopenharmony_ci		.type = IIO_EV_TYPE_ROC,
109062306a36Sopenharmony_ci		.dir = IIO_EV_DIR_EITHER,
109162306a36Sopenharmony_ci		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
109262306a36Sopenharmony_ci				 BIT(IIO_EV_INFO_ENABLE) |
109362306a36Sopenharmony_ci				 BIT(IIO_EV_INFO_PERIOD)
109462306a36Sopenharmony_ci};
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci#define BMC150_ACCEL_CHANNEL(_axis, bits) {				\
109762306a36Sopenharmony_ci	.type = IIO_ACCEL,						\
109862306a36Sopenharmony_ci	.modified = 1,							\
109962306a36Sopenharmony_ci	.channel2 = IIO_MOD_##_axis,					\
110062306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
110162306a36Sopenharmony_ci	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |		\
110262306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SAMP_FREQ),		\
110362306a36Sopenharmony_ci	.scan_index = AXIS_##_axis,					\
110462306a36Sopenharmony_ci	.scan_type = {							\
110562306a36Sopenharmony_ci		.sign = 's',						\
110662306a36Sopenharmony_ci		.realbits = (bits),					\
110762306a36Sopenharmony_ci		.storagebits = 16,					\
110862306a36Sopenharmony_ci		.shift = 16 - (bits),					\
110962306a36Sopenharmony_ci		.endianness = IIO_LE,					\
111062306a36Sopenharmony_ci	},								\
111162306a36Sopenharmony_ci	.ext_info = bmc150_accel_ext_info,				\
111262306a36Sopenharmony_ci	.event_spec = &bmc150_accel_event,				\
111362306a36Sopenharmony_ci	.num_event_specs = 1						\
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci#define BMC150_ACCEL_CHANNELS(bits) {					\
111762306a36Sopenharmony_ci	{								\
111862306a36Sopenharmony_ci		.type = IIO_TEMP,					\
111962306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
112062306a36Sopenharmony_ci				      BIT(IIO_CHAN_INFO_SCALE) |	\
112162306a36Sopenharmony_ci				      BIT(IIO_CHAN_INFO_OFFSET),	\
112262306a36Sopenharmony_ci		.scan_index = -1,					\
112362306a36Sopenharmony_ci	},								\
112462306a36Sopenharmony_ci	BMC150_ACCEL_CHANNEL(X, bits),					\
112562306a36Sopenharmony_ci	BMC150_ACCEL_CHANNEL(Y, bits),					\
112662306a36Sopenharmony_ci	BMC150_ACCEL_CHANNEL(Z, bits),					\
112762306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(3),					\
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic const struct iio_chan_spec bma222e_accel_channels[] =
113162306a36Sopenharmony_ci	BMC150_ACCEL_CHANNELS(8);
113262306a36Sopenharmony_cistatic const struct iio_chan_spec bma250e_accel_channels[] =
113362306a36Sopenharmony_ci	BMC150_ACCEL_CHANNELS(10);
113462306a36Sopenharmony_cistatic const struct iio_chan_spec bmc150_accel_channels[] =
113562306a36Sopenharmony_ci	BMC150_ACCEL_CHANNELS(12);
113662306a36Sopenharmony_cistatic const struct iio_chan_spec bma280_accel_channels[] =
113762306a36Sopenharmony_ci	BMC150_ACCEL_CHANNELS(14);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci/*
114062306a36Sopenharmony_ci * The range for the Bosch sensors is typically +-2g/4g/8g/16g, distributed
114162306a36Sopenharmony_ci * over the amount of bits (see above). The scale table can be calculated using
114262306a36Sopenharmony_ci *     (range / 2^bits) * g = (range / 2^bits) * 9.80665 m/s^2
114362306a36Sopenharmony_ci * e.g. for +-2g and 12 bits: (4 / 2^12) * 9.80665 m/s^2 = 0.0095768... m/s^2
114462306a36Sopenharmony_ci * Multiply 10^6 and round to get the values listed below.
114562306a36Sopenharmony_ci */
114662306a36Sopenharmony_cistatic const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
114762306a36Sopenharmony_ci	{
114862306a36Sopenharmony_ci		.name = "BMA222",
114962306a36Sopenharmony_ci		.chip_id = 0x03,
115062306a36Sopenharmony_ci		.channels = bma222e_accel_channels,
115162306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(bma222e_accel_channels),
115262306a36Sopenharmony_ci		.scale_table = { {153229, BMC150_ACCEL_DEF_RANGE_2G},
115362306a36Sopenharmony_ci				 {306458, BMC150_ACCEL_DEF_RANGE_4G},
115462306a36Sopenharmony_ci				 {612916, BMC150_ACCEL_DEF_RANGE_8G},
115562306a36Sopenharmony_ci				 {1225831, BMC150_ACCEL_DEF_RANGE_16G} },
115662306a36Sopenharmony_ci	},
115762306a36Sopenharmony_ci	{
115862306a36Sopenharmony_ci		.name = "BMA222E",
115962306a36Sopenharmony_ci		.chip_id = 0xF8,
116062306a36Sopenharmony_ci		.channels = bma222e_accel_channels,
116162306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(bma222e_accel_channels),
116262306a36Sopenharmony_ci		.scale_table = { {153229, BMC150_ACCEL_DEF_RANGE_2G},
116362306a36Sopenharmony_ci				 {306458, BMC150_ACCEL_DEF_RANGE_4G},
116462306a36Sopenharmony_ci				 {612916, BMC150_ACCEL_DEF_RANGE_8G},
116562306a36Sopenharmony_ci				 {1225831, BMC150_ACCEL_DEF_RANGE_16G} },
116662306a36Sopenharmony_ci	},
116762306a36Sopenharmony_ci	{
116862306a36Sopenharmony_ci		.name = "BMA250E",
116962306a36Sopenharmony_ci		.chip_id = 0xF9,
117062306a36Sopenharmony_ci		.channels = bma250e_accel_channels,
117162306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(bma250e_accel_channels),
117262306a36Sopenharmony_ci		.scale_table = { {38307, BMC150_ACCEL_DEF_RANGE_2G},
117362306a36Sopenharmony_ci				 {76614, BMC150_ACCEL_DEF_RANGE_4G},
117462306a36Sopenharmony_ci				 {153229, BMC150_ACCEL_DEF_RANGE_8G},
117562306a36Sopenharmony_ci				 {306458, BMC150_ACCEL_DEF_RANGE_16G} },
117662306a36Sopenharmony_ci	},
117762306a36Sopenharmony_ci	{
117862306a36Sopenharmony_ci		.name = "BMA253/BMA254/BMA255/BMC150/BMC156/BMI055",
117962306a36Sopenharmony_ci		.chip_id = 0xFA,
118062306a36Sopenharmony_ci		.channels = bmc150_accel_channels,
118162306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(bmc150_accel_channels),
118262306a36Sopenharmony_ci		.scale_table = { {9577, BMC150_ACCEL_DEF_RANGE_2G},
118362306a36Sopenharmony_ci				 {19154, BMC150_ACCEL_DEF_RANGE_4G},
118462306a36Sopenharmony_ci				 {38307, BMC150_ACCEL_DEF_RANGE_8G},
118562306a36Sopenharmony_ci				 {76614, BMC150_ACCEL_DEF_RANGE_16G} },
118662306a36Sopenharmony_ci	},
118762306a36Sopenharmony_ci	{
118862306a36Sopenharmony_ci		.name = "BMA280",
118962306a36Sopenharmony_ci		.chip_id = 0xFB,
119062306a36Sopenharmony_ci		.channels = bma280_accel_channels,
119162306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(bma280_accel_channels),
119262306a36Sopenharmony_ci		.scale_table = { {2394, BMC150_ACCEL_DEF_RANGE_2G},
119362306a36Sopenharmony_ci				 {4788, BMC150_ACCEL_DEF_RANGE_4G},
119462306a36Sopenharmony_ci				 {9577, BMC150_ACCEL_DEF_RANGE_8G},
119562306a36Sopenharmony_ci				 {19154, BMC150_ACCEL_DEF_RANGE_16G} },
119662306a36Sopenharmony_ci	},
119762306a36Sopenharmony_ci};
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic const struct iio_info bmc150_accel_info = {
120062306a36Sopenharmony_ci	.attrs			= &bmc150_accel_attrs_group,
120162306a36Sopenharmony_ci	.read_raw		= bmc150_accel_read_raw,
120262306a36Sopenharmony_ci	.write_raw		= bmc150_accel_write_raw,
120362306a36Sopenharmony_ci	.read_event_value	= bmc150_accel_read_event,
120462306a36Sopenharmony_ci	.write_event_value	= bmc150_accel_write_event,
120562306a36Sopenharmony_ci	.write_event_config	= bmc150_accel_write_event_config,
120662306a36Sopenharmony_ci	.read_event_config	= bmc150_accel_read_event_config,
120762306a36Sopenharmony_ci};
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_cistatic const struct iio_info bmc150_accel_info_fifo = {
121062306a36Sopenharmony_ci	.attrs			= &bmc150_accel_attrs_group,
121162306a36Sopenharmony_ci	.read_raw		= bmc150_accel_read_raw,
121262306a36Sopenharmony_ci	.write_raw		= bmc150_accel_write_raw,
121362306a36Sopenharmony_ci	.read_event_value	= bmc150_accel_read_event,
121462306a36Sopenharmony_ci	.write_event_value	= bmc150_accel_write_event,
121562306a36Sopenharmony_ci	.write_event_config	= bmc150_accel_write_event_config,
121662306a36Sopenharmony_ci	.read_event_config	= bmc150_accel_read_event_config,
121762306a36Sopenharmony_ci	.validate_trigger	= bmc150_accel_validate_trigger,
121862306a36Sopenharmony_ci	.hwfifo_set_watermark	= bmc150_accel_set_watermark,
121962306a36Sopenharmony_ci	.hwfifo_flush_to_buffer	= bmc150_accel_fifo_flush,
122062306a36Sopenharmony_ci};
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic const unsigned long bmc150_accel_scan_masks[] = {
122362306a36Sopenharmony_ci					BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
122462306a36Sopenharmony_ci					0};
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_cistatic irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	struct iio_poll_func *pf = p;
122962306a36Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
123062306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
123162306a36Sopenharmony_ci	int ret;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	mutex_lock(&data->mutex);
123462306a36Sopenharmony_ci	ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_REG_XOUT_L,
123562306a36Sopenharmony_ci			       data->buffer, AXIS_MAX * 2);
123662306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
123762306a36Sopenharmony_ci	if (ret < 0)
123862306a36Sopenharmony_ci		goto err_read;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
124162306a36Sopenharmony_ci					   pf->timestamp);
124262306a36Sopenharmony_cierr_read:
124362306a36Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	return IRQ_HANDLED;
124662306a36Sopenharmony_ci}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cistatic void bmc150_accel_trig_reen(struct iio_trigger *trig)
124962306a36Sopenharmony_ci{
125062306a36Sopenharmony_ci	struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
125162306a36Sopenharmony_ci	struct bmc150_accel_data *data = t->data;
125262306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
125362306a36Sopenharmony_ci	int ret;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	/* new data interrupts don't need ack */
125662306a36Sopenharmony_ci	if (t == &t->data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY])
125762306a36Sopenharmony_ci		return;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	mutex_lock(&data->mutex);
126062306a36Sopenharmony_ci	/* clear any latched interrupt */
126162306a36Sopenharmony_ci	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
126262306a36Sopenharmony_ci			   BMC150_ACCEL_INT_MODE_LATCH_INT |
126362306a36Sopenharmony_ci			   BMC150_ACCEL_INT_MODE_LATCH_RESET);
126462306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
126562306a36Sopenharmony_ci	if (ret < 0)
126662306a36Sopenharmony_ci		dev_err(dev, "Error writing reg_int_rst_latch\n");
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_cistatic int bmc150_accel_trigger_set_state(struct iio_trigger *trig,
127062306a36Sopenharmony_ci					  bool state)
127162306a36Sopenharmony_ci{
127262306a36Sopenharmony_ci	struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
127362306a36Sopenharmony_ci	struct bmc150_accel_data *data = t->data;
127462306a36Sopenharmony_ci	int ret;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	mutex_lock(&data->mutex);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	if (t->enabled == state) {
127962306a36Sopenharmony_ci		mutex_unlock(&data->mutex);
128062306a36Sopenharmony_ci		return 0;
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	if (t->setup) {
128462306a36Sopenharmony_ci		ret = t->setup(t, state);
128562306a36Sopenharmony_ci		if (ret < 0) {
128662306a36Sopenharmony_ci			mutex_unlock(&data->mutex);
128762306a36Sopenharmony_ci			return ret;
128862306a36Sopenharmony_ci		}
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	ret = bmc150_accel_set_interrupt(data, t->intr, state);
129262306a36Sopenharmony_ci	if (ret < 0) {
129362306a36Sopenharmony_ci		mutex_unlock(&data->mutex);
129462306a36Sopenharmony_ci		return ret;
129562306a36Sopenharmony_ci	}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	t->enabled = state;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	return ret;
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_cistatic const struct iio_trigger_ops bmc150_accel_trigger_ops = {
130562306a36Sopenharmony_ci	.set_trigger_state = bmc150_accel_trigger_set_state,
130662306a36Sopenharmony_ci	.reenable = bmc150_accel_trig_reen,
130762306a36Sopenharmony_ci};
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_cistatic int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
131262306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
131362306a36Sopenharmony_ci	int dir;
131462306a36Sopenharmony_ci	int ret;
131562306a36Sopenharmony_ci	unsigned int val;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	ret = regmap_read(data->regmap, BMC150_ACCEL_REG_INT_STATUS_2, &val);
131862306a36Sopenharmony_ci	if (ret < 0) {
131962306a36Sopenharmony_ci		dev_err(dev, "Error reading reg_int_status_2\n");
132062306a36Sopenharmony_ci		return ret;
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (val & BMC150_ACCEL_ANY_MOTION_BIT_SIGN)
132462306a36Sopenharmony_ci		dir = IIO_EV_DIR_FALLING;
132562306a36Sopenharmony_ci	else
132662306a36Sopenharmony_ci		dir = IIO_EV_DIR_RISING;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (val & BMC150_ACCEL_ANY_MOTION_BIT_X)
132962306a36Sopenharmony_ci		iio_push_event(indio_dev,
133062306a36Sopenharmony_ci			       IIO_MOD_EVENT_CODE(IIO_ACCEL,
133162306a36Sopenharmony_ci						  0,
133262306a36Sopenharmony_ci						  IIO_MOD_X,
133362306a36Sopenharmony_ci						  IIO_EV_TYPE_ROC,
133462306a36Sopenharmony_ci						  dir),
133562306a36Sopenharmony_ci			       data->timestamp);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (val & BMC150_ACCEL_ANY_MOTION_BIT_Y)
133862306a36Sopenharmony_ci		iio_push_event(indio_dev,
133962306a36Sopenharmony_ci			       IIO_MOD_EVENT_CODE(IIO_ACCEL,
134062306a36Sopenharmony_ci						  0,
134162306a36Sopenharmony_ci						  IIO_MOD_Y,
134262306a36Sopenharmony_ci						  IIO_EV_TYPE_ROC,
134362306a36Sopenharmony_ci						  dir),
134462306a36Sopenharmony_ci			       data->timestamp);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	if (val & BMC150_ACCEL_ANY_MOTION_BIT_Z)
134762306a36Sopenharmony_ci		iio_push_event(indio_dev,
134862306a36Sopenharmony_ci			       IIO_MOD_EVENT_CODE(IIO_ACCEL,
134962306a36Sopenharmony_ci						  0,
135062306a36Sopenharmony_ci						  IIO_MOD_Z,
135162306a36Sopenharmony_ci						  IIO_EV_TYPE_ROC,
135262306a36Sopenharmony_ci						  dir),
135362306a36Sopenharmony_ci			       data->timestamp);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	return ret;
135662306a36Sopenharmony_ci}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_cistatic irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	struct iio_dev *indio_dev = private;
136162306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
136262306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
136362306a36Sopenharmony_ci	bool ack = false;
136462306a36Sopenharmony_ci	int ret;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	mutex_lock(&data->mutex);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	if (data->fifo_mode) {
136962306a36Sopenharmony_ci		ret = __bmc150_accel_fifo_flush(indio_dev,
137062306a36Sopenharmony_ci						BMC150_ACCEL_FIFO_LENGTH, true);
137162306a36Sopenharmony_ci		if (ret > 0)
137262306a36Sopenharmony_ci			ack = true;
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	if (data->ev_enable_state) {
137662306a36Sopenharmony_ci		ret = bmc150_accel_handle_roc_event(indio_dev);
137762306a36Sopenharmony_ci		if (ret > 0)
137862306a36Sopenharmony_ci			ack = true;
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	if (ack) {
138262306a36Sopenharmony_ci		ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
138362306a36Sopenharmony_ci				   BMC150_ACCEL_INT_MODE_LATCH_INT |
138462306a36Sopenharmony_ci				   BMC150_ACCEL_INT_MODE_LATCH_RESET);
138562306a36Sopenharmony_ci		if (ret)
138662306a36Sopenharmony_ci			dev_err(dev, "Error writing reg_int_rst_latch\n");
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci		ret = IRQ_HANDLED;
138962306a36Sopenharmony_ci	} else {
139062306a36Sopenharmony_ci		ret = IRQ_NONE;
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	return ret;
139662306a36Sopenharmony_ci}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic irqreturn_t bmc150_accel_irq_handler(int irq, void *private)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	struct iio_dev *indio_dev = private;
140162306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
140262306a36Sopenharmony_ci	bool ack = false;
140362306a36Sopenharmony_ci	int i;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	data->old_timestamp = data->timestamp;
140662306a36Sopenharmony_ci	data->timestamp = iio_get_time_ns(indio_dev);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
140962306a36Sopenharmony_ci		if (data->triggers[i].enabled) {
141062306a36Sopenharmony_ci			iio_trigger_poll(data->triggers[i].indio_trig);
141162306a36Sopenharmony_ci			ack = true;
141262306a36Sopenharmony_ci			break;
141362306a36Sopenharmony_ci		}
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	if (data->ev_enable_state || data->fifo_mode)
141762306a36Sopenharmony_ci		return IRQ_WAKE_THREAD;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	if (ack)
142062306a36Sopenharmony_ci		return IRQ_HANDLED;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	return IRQ_NONE;
142362306a36Sopenharmony_ci}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_cistatic const struct {
142662306a36Sopenharmony_ci	int intr;
142762306a36Sopenharmony_ci	const char *name;
142862306a36Sopenharmony_ci	int (*setup)(struct bmc150_accel_trigger *t, bool state);
142962306a36Sopenharmony_ci} bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = {
143062306a36Sopenharmony_ci	{
143162306a36Sopenharmony_ci		.intr = 0,
143262306a36Sopenharmony_ci		.name = "%s-dev%d",
143362306a36Sopenharmony_ci	},
143462306a36Sopenharmony_ci	{
143562306a36Sopenharmony_ci		.intr = 1,
143662306a36Sopenharmony_ci		.name = "%s-any-motion-dev%d",
143762306a36Sopenharmony_ci		.setup = bmc150_accel_any_motion_setup,
143862306a36Sopenharmony_ci	},
143962306a36Sopenharmony_ci};
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_cistatic void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data,
144262306a36Sopenharmony_ci					     int from)
144362306a36Sopenharmony_ci{
144462306a36Sopenharmony_ci	int i;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	for (i = from; i >= 0; i--) {
144762306a36Sopenharmony_ci		if (data->triggers[i].indio_trig) {
144862306a36Sopenharmony_ci			iio_trigger_unregister(data->triggers[i].indio_trig);
144962306a36Sopenharmony_ci			data->triggers[i].indio_trig = NULL;
145062306a36Sopenharmony_ci		}
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_cistatic int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
145562306a36Sopenharmony_ci				       struct bmc150_accel_data *data)
145662306a36Sopenharmony_ci{
145762306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
145862306a36Sopenharmony_ci	int i, ret;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
146162306a36Sopenharmony_ci		struct bmc150_accel_trigger *t = &data->triggers[i];
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci		t->indio_trig = devm_iio_trigger_alloc(dev,
146462306a36Sopenharmony_ci						       bmc150_accel_triggers[i].name,
146562306a36Sopenharmony_ci						       indio_dev->name,
146662306a36Sopenharmony_ci						       iio_device_id(indio_dev));
146762306a36Sopenharmony_ci		if (!t->indio_trig) {
146862306a36Sopenharmony_ci			ret = -ENOMEM;
146962306a36Sopenharmony_ci			break;
147062306a36Sopenharmony_ci		}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci		t->indio_trig->ops = &bmc150_accel_trigger_ops;
147362306a36Sopenharmony_ci		t->intr = bmc150_accel_triggers[i].intr;
147462306a36Sopenharmony_ci		t->data = data;
147562306a36Sopenharmony_ci		t->setup = bmc150_accel_triggers[i].setup;
147662306a36Sopenharmony_ci		iio_trigger_set_drvdata(t->indio_trig, t);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci		ret = iio_trigger_register(t->indio_trig);
147962306a36Sopenharmony_ci		if (ret)
148062306a36Sopenharmony_ci			break;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	if (ret)
148462306a36Sopenharmony_ci		bmc150_accel_unregister_triggers(data, i - 1);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	return ret;
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci#define BMC150_ACCEL_FIFO_MODE_STREAM          0x80
149062306a36Sopenharmony_ci#define BMC150_ACCEL_FIFO_MODE_FIFO            0x40
149162306a36Sopenharmony_ci#define BMC150_ACCEL_FIFO_MODE_BYPASS          0x00
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_cistatic int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
149462306a36Sopenharmony_ci{
149562306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
149662306a36Sopenharmony_ci	u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
149762306a36Sopenharmony_ci	int ret;
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	ret = regmap_write(data->regmap, reg, data->fifo_mode);
150062306a36Sopenharmony_ci	if (ret < 0) {
150162306a36Sopenharmony_ci		dev_err(dev, "Error writing reg_fifo_config1\n");
150262306a36Sopenharmony_ci		return ret;
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	if (!data->fifo_mode)
150662306a36Sopenharmony_ci		return 0;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_FIFO_CONFIG0,
150962306a36Sopenharmony_ci			   data->watermark);
151062306a36Sopenharmony_ci	if (ret < 0)
151162306a36Sopenharmony_ci		dev_err(dev, "Error writing reg_fifo_config0\n");
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	return ret;
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_cistatic int bmc150_accel_buffer_preenable(struct iio_dev *indio_dev)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	return bmc150_accel_set_power_state(data, true);
152162306a36Sopenharmony_ci}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_cistatic int bmc150_accel_buffer_postenable(struct iio_dev *indio_dev)
152462306a36Sopenharmony_ci{
152562306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
152662306a36Sopenharmony_ci	int ret = 0;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (iio_device_get_current_mode(indio_dev) == INDIO_BUFFER_TRIGGERED)
152962306a36Sopenharmony_ci		return 0;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	mutex_lock(&data->mutex);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	if (!data->watermark)
153462306a36Sopenharmony_ci		goto out;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK,
153762306a36Sopenharmony_ci					 true);
153862306a36Sopenharmony_ci	if (ret)
153962306a36Sopenharmony_ci		goto out;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	data->fifo_mode = BMC150_ACCEL_FIFO_MODE_FIFO;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	ret = bmc150_accel_fifo_set_mode(data);
154462306a36Sopenharmony_ci	if (ret) {
154562306a36Sopenharmony_ci		data->fifo_mode = 0;
154662306a36Sopenharmony_ci		bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK,
154762306a36Sopenharmony_ci					   false);
154862306a36Sopenharmony_ci	}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ciout:
155162306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	return ret;
155462306a36Sopenharmony_ci}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_cistatic int bmc150_accel_buffer_predisable(struct iio_dev *indio_dev)
155762306a36Sopenharmony_ci{
155862306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	if (iio_device_get_current_mode(indio_dev) == INDIO_BUFFER_TRIGGERED)
156162306a36Sopenharmony_ci		return 0;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	mutex_lock(&data->mutex);
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	if (!data->fifo_mode)
156662306a36Sopenharmony_ci		goto out;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, false);
156962306a36Sopenharmony_ci	__bmc150_accel_fifo_flush(indio_dev, BMC150_ACCEL_FIFO_LENGTH, false);
157062306a36Sopenharmony_ci	data->fifo_mode = 0;
157162306a36Sopenharmony_ci	bmc150_accel_fifo_set_mode(data);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ciout:
157462306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	return 0;
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic int bmc150_accel_buffer_postdisable(struct iio_dev *indio_dev)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	return bmc150_accel_set_power_state(data, false);
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_cistatic const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
158762306a36Sopenharmony_ci	.preenable = bmc150_accel_buffer_preenable,
158862306a36Sopenharmony_ci	.postenable = bmc150_accel_buffer_postenable,
158962306a36Sopenharmony_ci	.predisable = bmc150_accel_buffer_predisable,
159062306a36Sopenharmony_ci	.postdisable = bmc150_accel_buffer_postdisable,
159162306a36Sopenharmony_ci};
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_cistatic int bmc150_accel_chip_init(struct bmc150_accel_data *data)
159462306a36Sopenharmony_ci{
159562306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
159662306a36Sopenharmony_ci	int ret, i;
159762306a36Sopenharmony_ci	unsigned int val;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	/*
160062306a36Sopenharmony_ci	 * Reset chip to get it in a known good state. A delay of 1.8ms after
160162306a36Sopenharmony_ci	 * reset is required according to the data sheets of supported chips.
160262306a36Sopenharmony_ci	 */
160362306a36Sopenharmony_ci	regmap_write(data->regmap, BMC150_ACCEL_REG_RESET,
160462306a36Sopenharmony_ci		     BMC150_ACCEL_RESET_VAL);
160562306a36Sopenharmony_ci	usleep_range(1800, 2500);
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val);
160862306a36Sopenharmony_ci	if (ret < 0) {
160962306a36Sopenharmony_ci		dev_err(dev, "Error: Reading chip id\n");
161062306a36Sopenharmony_ci		return ret;
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	dev_dbg(dev, "Chip Id %x\n", val);
161462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) {
161562306a36Sopenharmony_ci		if (bmc150_accel_chip_info_tbl[i].chip_id == val) {
161662306a36Sopenharmony_ci			data->chip_info = &bmc150_accel_chip_info_tbl[i];
161762306a36Sopenharmony_ci			break;
161862306a36Sopenharmony_ci		}
161962306a36Sopenharmony_ci	}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	if (!data->chip_info) {
162262306a36Sopenharmony_ci		dev_err(dev, "Invalid chip %x\n", val);
162362306a36Sopenharmony_ci		return -ENODEV;
162462306a36Sopenharmony_ci	}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
162762306a36Sopenharmony_ci	if (ret < 0)
162862306a36Sopenharmony_ci		return ret;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	/* Set Bandwidth */
163162306a36Sopenharmony_ci	ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0);
163262306a36Sopenharmony_ci	if (ret < 0)
163362306a36Sopenharmony_ci		return ret;
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	/* Set Default Range */
163662306a36Sopenharmony_ci	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE,
163762306a36Sopenharmony_ci			   BMC150_ACCEL_DEF_RANGE_4G);
163862306a36Sopenharmony_ci	if (ret < 0) {
163962306a36Sopenharmony_ci		dev_err(dev, "Error writing reg_pmu_range\n");
164062306a36Sopenharmony_ci		return ret;
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	data->range = BMC150_ACCEL_DEF_RANGE_4G;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	/* Set default slope duration and thresholds */
164662306a36Sopenharmony_ci	data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
164762306a36Sopenharmony_ci	data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION;
164862306a36Sopenharmony_ci	ret = bmc150_accel_update_slope(data);
164962306a36Sopenharmony_ci	if (ret < 0)
165062306a36Sopenharmony_ci		return ret;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	/* Set default as latched interrupts */
165362306a36Sopenharmony_ci	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
165462306a36Sopenharmony_ci			   BMC150_ACCEL_INT_MODE_LATCH_INT |
165562306a36Sopenharmony_ci			   BMC150_ACCEL_INT_MODE_LATCH_RESET);
165662306a36Sopenharmony_ci	if (ret < 0) {
165762306a36Sopenharmony_ci		dev_err(dev, "Error writing reg_int_rst_latch\n");
165862306a36Sopenharmony_ci		return ret;
165962306a36Sopenharmony_ci	}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	return 0;
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ciint bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
166562306a36Sopenharmony_ci			    enum bmc150_type type, const char *name,
166662306a36Sopenharmony_ci			    bool block_supported)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	const struct iio_dev_attr **fifo_attrs;
166962306a36Sopenharmony_ci	struct bmc150_accel_data *data;
167062306a36Sopenharmony_ci	struct iio_dev *indio_dev;
167162306a36Sopenharmony_ci	int ret;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
167462306a36Sopenharmony_ci	if (!indio_dev)
167562306a36Sopenharmony_ci		return -ENOMEM;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	data = iio_priv(indio_dev);
167862306a36Sopenharmony_ci	dev_set_drvdata(dev, indio_dev);
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	data->regmap = regmap;
168162306a36Sopenharmony_ci	data->type = type;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) {
168462306a36Sopenharmony_ci		ret = iio_read_mount_matrix(dev, &data->orientation);
168562306a36Sopenharmony_ci		if (ret)
168662306a36Sopenharmony_ci			return ret;
168762306a36Sopenharmony_ci	}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	/*
169062306a36Sopenharmony_ci	 * VDD   is the analog and digital domain voltage supply
169162306a36Sopenharmony_ci	 * VDDIO is the digital I/O voltage supply
169262306a36Sopenharmony_ci	 */
169362306a36Sopenharmony_ci	data->regulators[0].supply = "vdd";
169462306a36Sopenharmony_ci	data->regulators[1].supply = "vddio";
169562306a36Sopenharmony_ci	ret = devm_regulator_bulk_get(dev,
169662306a36Sopenharmony_ci				      ARRAY_SIZE(data->regulators),
169762306a36Sopenharmony_ci				      data->regulators);
169862306a36Sopenharmony_ci	if (ret)
169962306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to get regulators\n");
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
170262306a36Sopenharmony_ci				    data->regulators);
170362306a36Sopenharmony_ci	if (ret) {
170462306a36Sopenharmony_ci		dev_err(dev, "failed to enable regulators: %d\n", ret);
170562306a36Sopenharmony_ci		return ret;
170662306a36Sopenharmony_ci	}
170762306a36Sopenharmony_ci	/*
170862306a36Sopenharmony_ci	 * 2ms or 3ms power-on time according to datasheets, let's better
170962306a36Sopenharmony_ci	 * be safe than sorry and set this delay to 5ms.
171062306a36Sopenharmony_ci	 */
171162306a36Sopenharmony_ci	msleep(5);
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	ret = bmc150_accel_chip_init(data);
171462306a36Sopenharmony_ci	if (ret < 0)
171562306a36Sopenharmony_ci		goto err_disable_regulators;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	mutex_init(&data->mutex);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	indio_dev->channels = data->chip_info->channels;
172062306a36Sopenharmony_ci	indio_dev->num_channels = data->chip_info->num_channels;
172162306a36Sopenharmony_ci	indio_dev->name = name ? name : data->chip_info->name;
172262306a36Sopenharmony_ci	indio_dev->available_scan_masks = bmc150_accel_scan_masks;
172362306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
172462306a36Sopenharmony_ci	indio_dev->info = &bmc150_accel_info;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	if (block_supported) {
172762306a36Sopenharmony_ci		indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
172862306a36Sopenharmony_ci		indio_dev->info = &bmc150_accel_info_fifo;
172962306a36Sopenharmony_ci		fifo_attrs = bmc150_accel_fifo_attributes;
173062306a36Sopenharmony_ci	} else {
173162306a36Sopenharmony_ci		fifo_attrs = NULL;
173262306a36Sopenharmony_ci	}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	ret = iio_triggered_buffer_setup_ext(indio_dev,
173562306a36Sopenharmony_ci					     &iio_pollfunc_store_time,
173662306a36Sopenharmony_ci					     bmc150_accel_trigger_handler,
173762306a36Sopenharmony_ci					     IIO_BUFFER_DIRECTION_IN,
173862306a36Sopenharmony_ci					     &bmc150_accel_buffer_ops,
173962306a36Sopenharmony_ci					     fifo_attrs);
174062306a36Sopenharmony_ci	if (ret < 0) {
174162306a36Sopenharmony_ci		dev_err(dev, "Failed: iio triggered buffer setup\n");
174262306a36Sopenharmony_ci		goto err_disable_regulators;
174362306a36Sopenharmony_ci	}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	if (irq > 0) {
174662306a36Sopenharmony_ci		ret = devm_request_threaded_irq(dev, irq,
174762306a36Sopenharmony_ci						bmc150_accel_irq_handler,
174862306a36Sopenharmony_ci						bmc150_accel_irq_thread_handler,
174962306a36Sopenharmony_ci						IRQF_TRIGGER_RISING,
175062306a36Sopenharmony_ci						BMC150_ACCEL_IRQ_NAME,
175162306a36Sopenharmony_ci						indio_dev);
175262306a36Sopenharmony_ci		if (ret)
175362306a36Sopenharmony_ci			goto err_buffer_cleanup;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci		/*
175662306a36Sopenharmony_ci		 * Set latched mode interrupt. While certain interrupts are
175762306a36Sopenharmony_ci		 * non-latched regardless of this settings (e.g. new data) we
175862306a36Sopenharmony_ci		 * want to use latch mode when we can to prevent interrupt
175962306a36Sopenharmony_ci		 * flooding.
176062306a36Sopenharmony_ci		 */
176162306a36Sopenharmony_ci		ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
176262306a36Sopenharmony_ci				   BMC150_ACCEL_INT_MODE_LATCH_RESET);
176362306a36Sopenharmony_ci		if (ret < 0) {
176462306a36Sopenharmony_ci			dev_err(dev, "Error writing reg_int_rst_latch\n");
176562306a36Sopenharmony_ci			goto err_buffer_cleanup;
176662306a36Sopenharmony_ci		}
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci		bmc150_accel_interrupts_setup(indio_dev, data, irq);
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci		ret = bmc150_accel_triggers_setup(indio_dev, data);
177162306a36Sopenharmony_ci		if (ret)
177262306a36Sopenharmony_ci			goto err_buffer_cleanup;
177362306a36Sopenharmony_ci	}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	ret = pm_runtime_set_active(dev);
177662306a36Sopenharmony_ci	if (ret)
177762306a36Sopenharmony_ci		goto err_trigger_unregister;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	pm_runtime_enable(dev);
178062306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS);
178162306a36Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	ret = iio_device_register(indio_dev);
178462306a36Sopenharmony_ci	if (ret < 0) {
178562306a36Sopenharmony_ci		dev_err(dev, "Unable to register iio device\n");
178662306a36Sopenharmony_ci		goto err_pm_cleanup;
178762306a36Sopenharmony_ci	}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	return 0;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_cierr_pm_cleanup:
179262306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(dev);
179362306a36Sopenharmony_ci	pm_runtime_disable(dev);
179462306a36Sopenharmony_cierr_trigger_unregister:
179562306a36Sopenharmony_ci	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
179662306a36Sopenharmony_cierr_buffer_cleanup:
179762306a36Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
179862306a36Sopenharmony_cierr_disable_regulators:
179962306a36Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(data->regulators),
180062306a36Sopenharmony_ci			       data->regulators);
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	return ret;
180362306a36Sopenharmony_ci}
180462306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(bmc150_accel_core_probe, IIO_BMC150);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_civoid bmc150_accel_core_remove(struct device *dev)
180762306a36Sopenharmony_ci{
180862306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
180962306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	pm_runtime_disable(dev);
181462306a36Sopenharmony_ci	pm_runtime_set_suspended(dev);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	mutex_lock(&data->mutex);
182162306a36Sopenharmony_ci	bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0);
182262306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(data->regulators),
182562306a36Sopenharmony_ci			       data->regulators);
182662306a36Sopenharmony_ci}
182762306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(bmc150_accel_core_remove, IIO_BMC150);
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
183062306a36Sopenharmony_cistatic int bmc150_accel_suspend(struct device *dev)
183162306a36Sopenharmony_ci{
183262306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
183362306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	mutex_lock(&data->mutex);
183662306a36Sopenharmony_ci	bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
183762306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	return 0;
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_cistatic int bmc150_accel_resume(struct device *dev)
184362306a36Sopenharmony_ci{
184462306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
184562306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	mutex_lock(&data->mutex);
184862306a36Sopenharmony_ci	bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
184962306a36Sopenharmony_ci	bmc150_accel_fifo_set_mode(data);
185062306a36Sopenharmony_ci	mutex_unlock(&data->mutex);
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	if (data->resume_callback)
185362306a36Sopenharmony_ci		data->resume_callback(dev);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	return 0;
185662306a36Sopenharmony_ci}
185762306a36Sopenharmony_ci#endif
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci#ifdef CONFIG_PM
186062306a36Sopenharmony_cistatic int bmc150_accel_runtime_suspend(struct device *dev)
186162306a36Sopenharmony_ci{
186262306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
186362306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
186462306a36Sopenharmony_ci	int ret;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
186762306a36Sopenharmony_ci	if (ret < 0)
186862306a36Sopenharmony_ci		return -EAGAIN;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	return 0;
187162306a36Sopenharmony_ci}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_cistatic int bmc150_accel_runtime_resume(struct device *dev)
187462306a36Sopenharmony_ci{
187562306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
187662306a36Sopenharmony_ci	struct bmc150_accel_data *data = iio_priv(indio_dev);
187762306a36Sopenharmony_ci	int ret;
187862306a36Sopenharmony_ci	int sleep_val;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
188162306a36Sopenharmony_ci	if (ret < 0)
188262306a36Sopenharmony_ci		return ret;
188362306a36Sopenharmony_ci	ret = bmc150_accel_fifo_set_mode(data);
188462306a36Sopenharmony_ci	if (ret < 0)
188562306a36Sopenharmony_ci		return ret;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	sleep_val = bmc150_accel_get_startup_times(data);
188862306a36Sopenharmony_ci	if (sleep_val < 20)
188962306a36Sopenharmony_ci		usleep_range(sleep_val * 1000, 20000);
189062306a36Sopenharmony_ci	else
189162306a36Sopenharmony_ci		msleep_interruptible(sleep_val);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	return 0;
189462306a36Sopenharmony_ci}
189562306a36Sopenharmony_ci#endif
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ciconst struct dev_pm_ops bmc150_accel_pm_ops = {
189862306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume)
189962306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend,
190062306a36Sopenharmony_ci			   bmc150_accel_runtime_resume, NULL)
190162306a36Sopenharmony_ci};
190262306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(bmc150_accel_pm_ops, IIO_BMC150);
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ciMODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
190562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
190662306a36Sopenharmony_ciMODULE_DESCRIPTION("BMC150 accelerometer driver");
1907