xref: /linux/drivers/iio/imu/fxos8700_core.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
184e5ddd5SRobert Jones // SPDX-License-Identifier: GPL-2.0
284e5ddd5SRobert Jones /*
384e5ddd5SRobert Jones  * FXOS8700 - NXP IMU (accelerometer plus magnetometer)
484e5ddd5SRobert Jones  *
584e5ddd5SRobert Jones  * IIO core driver for FXOS8700, with support for I2C/SPI busses
684e5ddd5SRobert Jones  *
784e5ddd5SRobert Jones  * TODO: Buffer, trigger, and IRQ support
884e5ddd5SRobert Jones  */
984e5ddd5SRobert Jones #include <linux/module.h>
1084e5ddd5SRobert Jones #include <linux/regmap.h>
1184e5ddd5SRobert Jones #include <linux/acpi.h>
1284e5ddd5SRobert Jones #include <linux/bitops.h>
1378ad6864SCarlos Song #include <linux/bitfield.h>
1484e5ddd5SRobert Jones 
1584e5ddd5SRobert Jones #include <linux/iio/iio.h>
1684e5ddd5SRobert Jones #include <linux/iio/sysfs.h>
1784e5ddd5SRobert Jones 
1884e5ddd5SRobert Jones #include "fxos8700.h"
1984e5ddd5SRobert Jones 
2084e5ddd5SRobert Jones /* Register Definitions */
2184e5ddd5SRobert Jones #define FXOS8700_STATUS             0x00
2284e5ddd5SRobert Jones #define FXOS8700_OUT_X_MSB          0x01
2384e5ddd5SRobert Jones #define FXOS8700_OUT_X_LSB          0x02
2484e5ddd5SRobert Jones #define FXOS8700_OUT_Y_MSB          0x03
2584e5ddd5SRobert Jones #define FXOS8700_OUT_Y_LSB          0x04
2684e5ddd5SRobert Jones #define FXOS8700_OUT_Z_MSB          0x05
2784e5ddd5SRobert Jones #define FXOS8700_OUT_Z_LSB          0x06
2884e5ddd5SRobert Jones #define FXOS8700_F_SETUP            0x09
2984e5ddd5SRobert Jones #define FXOS8700_TRIG_CFG           0x0a
3084e5ddd5SRobert Jones #define FXOS8700_SYSMOD             0x0b
3184e5ddd5SRobert Jones #define FXOS8700_INT_SOURCE         0x0c
3284e5ddd5SRobert Jones #define FXOS8700_WHO_AM_I           0x0d
3384e5ddd5SRobert Jones #define FXOS8700_XYZ_DATA_CFG       0x0e
3484e5ddd5SRobert Jones #define FXOS8700_HP_FILTER_CUTOFF   0x0f
3584e5ddd5SRobert Jones #define FXOS8700_PL_STATUS          0x10
3684e5ddd5SRobert Jones #define FXOS8700_PL_CFG             0x11
3784e5ddd5SRobert Jones #define FXOS8700_PL_COUNT           0x12
3884e5ddd5SRobert Jones #define FXOS8700_PL_BF_ZCOMP        0x13
3984e5ddd5SRobert Jones #define FXOS8700_PL_THS_REG         0x14
4084e5ddd5SRobert Jones #define FXOS8700_A_FFMT_CFG         0x15
4184e5ddd5SRobert Jones #define FXOS8700_A_FFMT_SRC         0x16
4284e5ddd5SRobert Jones #define FXOS8700_A_FFMT_THS         0x17
4384e5ddd5SRobert Jones #define FXOS8700_A_FFMT_COUNT       0x18
4484e5ddd5SRobert Jones #define FXOS8700_TRANSIENT_CFG      0x1d
4584e5ddd5SRobert Jones #define FXOS8700_TRANSIENT_SRC      0x1e
4684e5ddd5SRobert Jones #define FXOS8700_TRANSIENT_THS      0x1f
4784e5ddd5SRobert Jones #define FXOS8700_TRANSIENT_COUNT    0x20
4884e5ddd5SRobert Jones #define FXOS8700_PULSE_CFG          0x21
4984e5ddd5SRobert Jones #define FXOS8700_PULSE_SRC          0x22
5084e5ddd5SRobert Jones #define FXOS8700_PULSE_THSX         0x23
5184e5ddd5SRobert Jones #define FXOS8700_PULSE_THSY         0x24
5284e5ddd5SRobert Jones #define FXOS8700_PULSE_THSZ         0x25
5384e5ddd5SRobert Jones #define FXOS8700_PULSE_TMLT         0x26
5484e5ddd5SRobert Jones #define FXOS8700_PULSE_LTCY         0x27
5584e5ddd5SRobert Jones #define FXOS8700_PULSE_WIND         0x28
5684e5ddd5SRobert Jones #define FXOS8700_ASLP_COUNT         0x29
5784e5ddd5SRobert Jones #define FXOS8700_CTRL_REG1          0x2a
5884e5ddd5SRobert Jones #define FXOS8700_CTRL_REG2          0x2b
5984e5ddd5SRobert Jones #define FXOS8700_CTRL_REG3          0x2c
6084e5ddd5SRobert Jones #define FXOS8700_CTRL_REG4          0x2d
6184e5ddd5SRobert Jones #define FXOS8700_CTRL_REG5          0x2e
6284e5ddd5SRobert Jones #define FXOS8700_OFF_X              0x2f
6384e5ddd5SRobert Jones #define FXOS8700_OFF_Y              0x30
6484e5ddd5SRobert Jones #define FXOS8700_OFF_Z              0x31
6584e5ddd5SRobert Jones #define FXOS8700_M_DR_STATUS        0x32
6684e5ddd5SRobert Jones #define FXOS8700_M_OUT_X_MSB        0x33
6784e5ddd5SRobert Jones #define FXOS8700_M_OUT_X_LSB        0x34
6884e5ddd5SRobert Jones #define FXOS8700_M_OUT_Y_MSB        0x35
6984e5ddd5SRobert Jones #define FXOS8700_M_OUT_Y_LSB        0x36
7084e5ddd5SRobert Jones #define FXOS8700_M_OUT_Z_MSB        0x37
7184e5ddd5SRobert Jones #define FXOS8700_M_OUT_Z_LSB        0x38
7284e5ddd5SRobert Jones #define FXOS8700_CMP_X_MSB          0x39
7384e5ddd5SRobert Jones #define FXOS8700_CMP_X_LSB          0x3a
7484e5ddd5SRobert Jones #define FXOS8700_CMP_Y_MSB          0x3b
7584e5ddd5SRobert Jones #define FXOS8700_CMP_Y_LSB          0x3c
7684e5ddd5SRobert Jones #define FXOS8700_CMP_Z_MSB          0x3d
7784e5ddd5SRobert Jones #define FXOS8700_CMP_Z_LSB          0x3e
7884e5ddd5SRobert Jones #define FXOS8700_M_OFF_X_MSB        0x3f
7984e5ddd5SRobert Jones #define FXOS8700_M_OFF_X_LSB        0x40
8084e5ddd5SRobert Jones #define FXOS8700_M_OFF_Y_MSB        0x41
8184e5ddd5SRobert Jones #define FXOS8700_M_OFF_Y_LSB        0x42
8284e5ddd5SRobert Jones #define FXOS8700_M_OFF_Z_MSB        0x43
8384e5ddd5SRobert Jones #define FXOS8700_M_OFF_Z_LSB        0x44
8484e5ddd5SRobert Jones #define FXOS8700_MAX_X_MSB          0x45
8584e5ddd5SRobert Jones #define FXOS8700_MAX_X_LSB          0x46
8684e5ddd5SRobert Jones #define FXOS8700_MAX_Y_MSB          0x47
8784e5ddd5SRobert Jones #define FXOS8700_MAX_Y_LSB          0x48
8884e5ddd5SRobert Jones #define FXOS8700_MAX_Z_MSB          0x49
8984e5ddd5SRobert Jones #define FXOS8700_MAX_Z_LSB          0x4a
9084e5ddd5SRobert Jones #define FXOS8700_MIN_X_MSB          0x4b
9184e5ddd5SRobert Jones #define FXOS8700_MIN_X_LSB          0x4c
9284e5ddd5SRobert Jones #define FXOS8700_MIN_Y_MSB          0x4d
9384e5ddd5SRobert Jones #define FXOS8700_MIN_Y_LSB          0x4e
9484e5ddd5SRobert Jones #define FXOS8700_MIN_Z_MSB          0x4f
9584e5ddd5SRobert Jones #define FXOS8700_MIN_Z_LSB          0x50
9684e5ddd5SRobert Jones #define FXOS8700_TEMP               0x51
9784e5ddd5SRobert Jones #define FXOS8700_M_THS_CFG          0x52
9884e5ddd5SRobert Jones #define FXOS8700_M_THS_SRC          0x53
9984e5ddd5SRobert Jones #define FXOS8700_M_THS_X_MSB        0x54
10084e5ddd5SRobert Jones #define FXOS8700_M_THS_X_LSB        0x55
10184e5ddd5SRobert Jones #define FXOS8700_M_THS_Y_MSB        0x56
10284e5ddd5SRobert Jones #define FXOS8700_M_THS_Y_LSB        0x57
10384e5ddd5SRobert Jones #define FXOS8700_M_THS_Z_MSB        0x58
10484e5ddd5SRobert Jones #define FXOS8700_M_THS_Z_LSB        0x59
10584e5ddd5SRobert Jones #define FXOS8700_M_THS_COUNT        0x5a
10684e5ddd5SRobert Jones #define FXOS8700_M_CTRL_REG1        0x5b
10784e5ddd5SRobert Jones #define FXOS8700_M_CTRL_REG2        0x5c
10884e5ddd5SRobert Jones #define FXOS8700_M_CTRL_REG3        0x5d
10984e5ddd5SRobert Jones #define FXOS8700_M_INT_SRC          0x5e
11084e5ddd5SRobert Jones #define FXOS8700_A_VECM_CFG         0x5f
11184e5ddd5SRobert Jones #define FXOS8700_A_VECM_THS_MSB     0x60
11284e5ddd5SRobert Jones #define FXOS8700_A_VECM_THS_LSB     0x61
11384e5ddd5SRobert Jones #define FXOS8700_A_VECM_CNT         0x62
11484e5ddd5SRobert Jones #define FXOS8700_A_VECM_INITX_MSB   0x63
11584e5ddd5SRobert Jones #define FXOS8700_A_VECM_INITX_LSB   0x64
11684e5ddd5SRobert Jones #define FXOS8700_A_VECM_INITY_MSB   0x65
11784e5ddd5SRobert Jones #define FXOS8700_A_VECM_INITY_LSB   0x66
11884e5ddd5SRobert Jones #define FXOS8700_A_VECM_INITZ_MSB   0x67
11984e5ddd5SRobert Jones #define FXOS8700_A_VECM_INITZ_LSB   0x68
12084e5ddd5SRobert Jones #define FXOS8700_M_VECM_CFG         0x69
12184e5ddd5SRobert Jones #define FXOS8700_M_VECM_THS_MSB     0x6a
12284e5ddd5SRobert Jones #define FXOS8700_M_VECM_THS_LSB     0x6b
12384e5ddd5SRobert Jones #define FXOS8700_M_VECM_CNT         0x6c
12484e5ddd5SRobert Jones #define FXOS8700_M_VECM_INITX_MSB   0x6d
12584e5ddd5SRobert Jones #define FXOS8700_M_VECM_INITX_LSB   0x6e
12684e5ddd5SRobert Jones #define FXOS8700_M_VECM_INITY_MSB   0x6f
12784e5ddd5SRobert Jones #define FXOS8700_M_VECM_INITY_LSB   0x70
12884e5ddd5SRobert Jones #define FXOS8700_M_VECM_INITZ_MSB   0x71
12984e5ddd5SRobert Jones #define FXOS8700_M_VECM_INITZ_LSB   0x72
13084e5ddd5SRobert Jones #define FXOS8700_A_FFMT_THS_X_MSB   0x73
13184e5ddd5SRobert Jones #define FXOS8700_A_FFMT_THS_X_LSB   0x74
13284e5ddd5SRobert Jones #define FXOS8700_A_FFMT_THS_Y_MSB   0x75
13384e5ddd5SRobert Jones #define FXOS8700_A_FFMT_THS_Y_LSB   0x76
13484e5ddd5SRobert Jones #define FXOS8700_A_FFMT_THS_Z_MSB   0x77
13584e5ddd5SRobert Jones #define FXOS8700_A_FFMT_THS_Z_LSB   0x78
13684e5ddd5SRobert Jones #define FXOS8700_A_TRAN_INIT_MSB    0x79
13784e5ddd5SRobert Jones #define FXOS8700_A_TRAN_INIT_LSB_X  0x7a
13884e5ddd5SRobert Jones #define FXOS8700_A_TRAN_INIT_LSB_Y  0x7b
13984e5ddd5SRobert Jones #define FXOS8700_A_TRAN_INIT_LSB_Z  0x7d
14084e5ddd5SRobert Jones #define FXOS8700_TM_NVM_LOCK        0x7e
14184e5ddd5SRobert Jones #define FXOS8700_NVM_DATA0_35       0x80
14284e5ddd5SRobert Jones #define FXOS8700_NVM_DATA_BNK3      0xa4
14384e5ddd5SRobert Jones #define FXOS8700_NVM_DATA_BNK2      0xa5
14484e5ddd5SRobert Jones #define FXOS8700_NVM_DATA_BNK1      0xa6
14584e5ddd5SRobert Jones #define FXOS8700_NVM_DATA_BNK0      0xa7
14684e5ddd5SRobert Jones 
14784e5ddd5SRobert Jones /* Bit definitions for FXOS8700_CTRL_REG1 */
14884e5ddd5SRobert Jones #define FXOS8700_CTRL_ODR_MAX       0x00
14978ad6864SCarlos Song #define FXOS8700_CTRL_ODR_MSK       GENMASK(5, 3)
15084e5ddd5SRobert Jones 
15184e5ddd5SRobert Jones /* Bit definitions for FXOS8700_M_CTRL_REG1 */
15284e5ddd5SRobert Jones #define FXOS8700_HMS_MASK           GENMASK(1, 0)
15384e5ddd5SRobert Jones #define FXOS8700_OS_MASK            GENMASK(4, 2)
15484e5ddd5SRobert Jones 
15584e5ddd5SRobert Jones /* Bit definitions for FXOS8700_M_CTRL_REG2 */
15684e5ddd5SRobert Jones #define FXOS8700_MAXMIN_RST         BIT(2)
15784e5ddd5SRobert Jones #define FXOS8700_MAXMIN_DIS_THS     BIT(3)
15884e5ddd5SRobert Jones #define FXOS8700_MAXMIN_DIS         BIT(4)
15984e5ddd5SRobert Jones 
16084e5ddd5SRobert Jones #define FXOS8700_ACTIVE             0x01
16184e5ddd5SRobert Jones #define FXOS8700_ACTIVE_MIN_USLEEP  4000 /* from table 6 in datasheet */
16284e5ddd5SRobert Jones 
16384e5ddd5SRobert Jones #define FXOS8700_DEVICE_ID          0xC7
16484e5ddd5SRobert Jones #define FXOS8700_PRE_DEVICE_ID      0xC4
16584e5ddd5SRobert Jones #define FXOS8700_DATA_BUF_SIZE      3
16684e5ddd5SRobert Jones 
16784e5ddd5SRobert Jones struct fxos8700_data {
16884e5ddd5SRobert Jones 	struct regmap *regmap;
16984e5ddd5SRobert Jones 	struct iio_trigger *trig;
170c9a8417aSJonathan Cameron 	__be16 buf[FXOS8700_DATA_BUF_SIZE] __aligned(IIO_DMA_MINALIGN);
17184e5ddd5SRobert Jones };
17284e5ddd5SRobert Jones 
17384e5ddd5SRobert Jones /* Regmap info */
17484e5ddd5SRobert Jones static const struct regmap_range read_range[] = {
17584e5ddd5SRobert Jones 	{
17684e5ddd5SRobert Jones 		.range_min = FXOS8700_STATUS,
17784e5ddd5SRobert Jones 		.range_max = FXOS8700_A_FFMT_COUNT,
17884e5ddd5SRobert Jones 	}, {
17984e5ddd5SRobert Jones 		.range_min = FXOS8700_TRANSIENT_CFG,
18084e5ddd5SRobert Jones 		.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
18184e5ddd5SRobert Jones 	},
18284e5ddd5SRobert Jones };
18384e5ddd5SRobert Jones 
18484e5ddd5SRobert Jones static const struct regmap_range write_range[] = {
18584e5ddd5SRobert Jones 	{
18684e5ddd5SRobert Jones 		.range_min = FXOS8700_F_SETUP,
18784e5ddd5SRobert Jones 		.range_max = FXOS8700_TRIG_CFG,
18884e5ddd5SRobert Jones 	}, {
18984e5ddd5SRobert Jones 		.range_min = FXOS8700_XYZ_DATA_CFG,
19084e5ddd5SRobert Jones 		.range_max = FXOS8700_HP_FILTER_CUTOFF,
19184e5ddd5SRobert Jones 	}, {
19284e5ddd5SRobert Jones 		.range_min = FXOS8700_PL_CFG,
19384e5ddd5SRobert Jones 		.range_max = FXOS8700_A_FFMT_CFG,
19484e5ddd5SRobert Jones 	}, {
19584e5ddd5SRobert Jones 		.range_min = FXOS8700_A_FFMT_THS,
19684e5ddd5SRobert Jones 		.range_max = FXOS8700_TRANSIENT_CFG,
19784e5ddd5SRobert Jones 	}, {
19884e5ddd5SRobert Jones 		.range_min = FXOS8700_TRANSIENT_THS,
19984e5ddd5SRobert Jones 		.range_max = FXOS8700_PULSE_CFG,
20084e5ddd5SRobert Jones 	}, {
20184e5ddd5SRobert Jones 		.range_min = FXOS8700_PULSE_THSX,
20284e5ddd5SRobert Jones 		.range_max = FXOS8700_OFF_Z,
20384e5ddd5SRobert Jones 	}, {
20484e5ddd5SRobert Jones 		.range_min = FXOS8700_M_OFF_X_MSB,
20584e5ddd5SRobert Jones 		.range_max = FXOS8700_M_OFF_Z_LSB,
20684e5ddd5SRobert Jones 	}, {
20784e5ddd5SRobert Jones 		.range_min = FXOS8700_M_THS_CFG,
20884e5ddd5SRobert Jones 		.range_max = FXOS8700_M_THS_CFG,
20984e5ddd5SRobert Jones 	}, {
21084e5ddd5SRobert Jones 		.range_min = FXOS8700_M_THS_X_MSB,
21184e5ddd5SRobert Jones 		.range_max = FXOS8700_M_CTRL_REG3,
21284e5ddd5SRobert Jones 	}, {
21384e5ddd5SRobert Jones 		.range_min = FXOS8700_A_VECM_CFG,
21484e5ddd5SRobert Jones 		.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
21584e5ddd5SRobert Jones 	},
21684e5ddd5SRobert Jones };
21784e5ddd5SRobert Jones 
21884e5ddd5SRobert Jones static const struct regmap_access_table driver_read_table = {
21984e5ddd5SRobert Jones 	.yes_ranges =   read_range,
22084e5ddd5SRobert Jones 	.n_yes_ranges = ARRAY_SIZE(read_range),
22184e5ddd5SRobert Jones };
22284e5ddd5SRobert Jones 
22384e5ddd5SRobert Jones static const struct regmap_access_table driver_write_table = {
22484e5ddd5SRobert Jones 	.yes_ranges =   write_range,
22584e5ddd5SRobert Jones 	.n_yes_ranges = ARRAY_SIZE(write_range),
22684e5ddd5SRobert Jones };
22784e5ddd5SRobert Jones 
22884e5ddd5SRobert Jones const struct regmap_config fxos8700_regmap_config = {
22984e5ddd5SRobert Jones 	.reg_bits = 8,
23084e5ddd5SRobert Jones 	.val_bits = 8,
23184e5ddd5SRobert Jones 	.max_register = FXOS8700_NVM_DATA_BNK0,
23284e5ddd5SRobert Jones 	.rd_table = &driver_read_table,
23384e5ddd5SRobert Jones 	.wr_table = &driver_write_table,
23484e5ddd5SRobert Jones };
23584e5ddd5SRobert Jones EXPORT_SYMBOL(fxos8700_regmap_config);
23684e5ddd5SRobert Jones 
23784e5ddd5SRobert Jones #define FXOS8700_CHANNEL(_type, _axis) {			\
23884e5ddd5SRobert Jones 	.type = _type,						\
23984e5ddd5SRobert Jones 	.modified = 1,						\
24084e5ddd5SRobert Jones 	.channel2 = IIO_MOD_##_axis,				\
24184e5ddd5SRobert Jones 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
24284e5ddd5SRobert Jones 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |  \
24384e5ddd5SRobert Jones 		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
24484e5ddd5SRobert Jones }
24584e5ddd5SRobert Jones 
24684e5ddd5SRobert Jones enum fxos8700_accel_scale_bits {
24784e5ddd5SRobert Jones 	MODE_2G = 0,
24884e5ddd5SRobert Jones 	MODE_4G,
24984e5ddd5SRobert Jones 	MODE_8G,
25084e5ddd5SRobert Jones };
25184e5ddd5SRobert Jones 
25284e5ddd5SRobert Jones /* scan indexes follow DATA register order */
25384e5ddd5SRobert Jones enum fxos8700_scan_axis {
25484e5ddd5SRobert Jones 	FXOS8700_SCAN_ACCEL_X = 0,
25584e5ddd5SRobert Jones 	FXOS8700_SCAN_ACCEL_Y,
25684e5ddd5SRobert Jones 	FXOS8700_SCAN_ACCEL_Z,
25784e5ddd5SRobert Jones 	FXOS8700_SCAN_MAGN_X,
25884e5ddd5SRobert Jones 	FXOS8700_SCAN_MAGN_Y,
25984e5ddd5SRobert Jones 	FXOS8700_SCAN_MAGN_Z,
26084e5ddd5SRobert Jones 	FXOS8700_SCAN_RHALL,
26184e5ddd5SRobert Jones 	FXOS8700_SCAN_TIMESTAMP,
26284e5ddd5SRobert Jones };
26384e5ddd5SRobert Jones 
26484e5ddd5SRobert Jones enum fxos8700_sensor {
26584e5ddd5SRobert Jones 	FXOS8700_ACCEL	= 0,
26684e5ddd5SRobert Jones 	FXOS8700_MAGN,
26784e5ddd5SRobert Jones 	FXOS8700_NUM_SENSORS /* must be last */
26884e5ddd5SRobert Jones };
26984e5ddd5SRobert Jones 
27084e5ddd5SRobert Jones enum fxos8700_int_pin {
27184e5ddd5SRobert Jones 	FXOS8700_PIN_INT1,
27284e5ddd5SRobert Jones 	FXOS8700_PIN_INT2
27384e5ddd5SRobert Jones };
27484e5ddd5SRobert Jones 
27584e5ddd5SRobert Jones struct fxos8700_scale {
27684e5ddd5SRobert Jones 	u8 bits;
27784e5ddd5SRobert Jones 	int uscale;
27884e5ddd5SRobert Jones };
27984e5ddd5SRobert Jones 
28084e5ddd5SRobert Jones struct fxos8700_odr {
28184e5ddd5SRobert Jones 	u8 bits;
28284e5ddd5SRobert Jones 	int odr;
28384e5ddd5SRobert Jones 	int uodr;
28484e5ddd5SRobert Jones };
28584e5ddd5SRobert Jones 
28684e5ddd5SRobert Jones static const struct fxos8700_scale fxos8700_accel_scale[] = {
28784e5ddd5SRobert Jones 	{ MODE_2G, 244},
28884e5ddd5SRobert Jones 	{ MODE_4G, 488},
28984e5ddd5SRobert Jones 	{ MODE_8G, 976},
29084e5ddd5SRobert Jones };
29184e5ddd5SRobert Jones 
29284e5ddd5SRobert Jones /*
29384e5ddd5SRobert Jones  * Accellerometer and magnetometer have the same ODR options, set in the
29484e5ddd5SRobert Jones  * CTRL_REG1 register. ODR is halved when using both sensors at once in
29584e5ddd5SRobert Jones  * hybrid mode.
29684e5ddd5SRobert Jones  */
29784e5ddd5SRobert Jones static const struct fxos8700_odr fxos8700_odr[] = {
29884e5ddd5SRobert Jones 	{0x00, 800, 0},
29984e5ddd5SRobert Jones 	{0x01, 400, 0},
30084e5ddd5SRobert Jones 	{0x02, 200, 0},
30184e5ddd5SRobert Jones 	{0x03, 100, 0},
30284e5ddd5SRobert Jones 	{0x04, 50, 0},
30384e5ddd5SRobert Jones 	{0x05, 12, 500000},
30484e5ddd5SRobert Jones 	{0x06, 6, 250000},
30584e5ddd5SRobert Jones 	{0x07, 1, 562500},
30684e5ddd5SRobert Jones };
30784e5ddd5SRobert Jones 
30884e5ddd5SRobert Jones static const struct iio_chan_spec fxos8700_channels[] = {
30984e5ddd5SRobert Jones 	FXOS8700_CHANNEL(IIO_ACCEL, X),
31084e5ddd5SRobert Jones 	FXOS8700_CHANNEL(IIO_ACCEL, Y),
31184e5ddd5SRobert Jones 	FXOS8700_CHANNEL(IIO_ACCEL, Z),
31284e5ddd5SRobert Jones 	FXOS8700_CHANNEL(IIO_MAGN, X),
31384e5ddd5SRobert Jones 	FXOS8700_CHANNEL(IIO_MAGN, Y),
31484e5ddd5SRobert Jones 	FXOS8700_CHANNEL(IIO_MAGN, Z),
31584e5ddd5SRobert Jones 	IIO_CHAN_SOFT_TIMESTAMP(FXOS8700_SCAN_TIMESTAMP),
31684e5ddd5SRobert Jones };
31784e5ddd5SRobert Jones 
fxos8700_to_sensor(enum iio_chan_type iio_type)31884e5ddd5SRobert Jones static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type)
31984e5ddd5SRobert Jones {
32084e5ddd5SRobert Jones 	switch (iio_type) {
32184e5ddd5SRobert Jones 	case IIO_ACCEL:
32284e5ddd5SRobert Jones 		return FXOS8700_ACCEL;
323429e1e8eSCarlos Song 	case IIO_MAGN:
32484e5ddd5SRobert Jones 		return FXOS8700_MAGN;
32584e5ddd5SRobert Jones 	default:
32684e5ddd5SRobert Jones 		return -EINVAL;
32784e5ddd5SRobert Jones 	}
32884e5ddd5SRobert Jones }
32984e5ddd5SRobert Jones 
fxos8700_set_active_mode(struct fxos8700_data * data,enum fxos8700_sensor t,bool mode)33084e5ddd5SRobert Jones static int fxos8700_set_active_mode(struct fxos8700_data *data,
33184e5ddd5SRobert Jones 				    enum fxos8700_sensor t, bool mode)
33284e5ddd5SRobert Jones {
33384e5ddd5SRobert Jones 	int ret;
33484e5ddd5SRobert Jones 
33584e5ddd5SRobert Jones 	ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, mode);
33684e5ddd5SRobert Jones 	if (ret)
33784e5ddd5SRobert Jones 		return ret;
33884e5ddd5SRobert Jones 
33984e5ddd5SRobert Jones 	usleep_range(FXOS8700_ACTIVE_MIN_USLEEP,
34084e5ddd5SRobert Jones 		     FXOS8700_ACTIVE_MIN_USLEEP + 1000);
34184e5ddd5SRobert Jones 
34284e5ddd5SRobert Jones 	return 0;
34384e5ddd5SRobert Jones }
34484e5ddd5SRobert Jones 
fxos8700_set_scale(struct fxos8700_data * data,enum fxos8700_sensor t,int uscale)34584e5ddd5SRobert Jones static int fxos8700_set_scale(struct fxos8700_data *data,
34684e5ddd5SRobert Jones 			      enum fxos8700_sensor t, int uscale)
34784e5ddd5SRobert Jones {
3489d61c182SCarlos Song 	int i, ret, val;
3499d61c182SCarlos Song 	bool active_mode;
35084e5ddd5SRobert Jones 	static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
35184e5ddd5SRobert Jones 	struct device *dev = regmap_get_device(data->regmap);
35284e5ddd5SRobert Jones 
35384e5ddd5SRobert Jones 	if (t == FXOS8700_MAGN) {
354*2acd0313SCarlos Song 		dev_err(dev, "Magnetometer scale is locked at 0.001Gs\n");
35584e5ddd5SRobert Jones 		return -EINVAL;
35684e5ddd5SRobert Jones 	}
35784e5ddd5SRobert Jones 
3589d61c182SCarlos Song 	/*
3599d61c182SCarlos Song 	 * When device is in active mode, it failed to set an ACCEL
3609d61c182SCarlos Song 	 * full-scale range(2g/4g/8g) in FXOS8700_XYZ_DATA_CFG.
3619d61c182SCarlos Song 	 * This is not align with the datasheet, but it is a fxos8700
3629d61c182SCarlos Song 	 * chip behavier. Set the device in standby mode before setting
3639d61c182SCarlos Song 	 * an ACCEL full-scale range.
3649d61c182SCarlos Song 	 */
3659d61c182SCarlos Song 	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
3669d61c182SCarlos Song 	if (ret)
3679d61c182SCarlos Song 		return ret;
3689d61c182SCarlos Song 
3699d61c182SCarlos Song 	active_mode = val & FXOS8700_ACTIVE;
3709d61c182SCarlos Song 	if (active_mode) {
3719d61c182SCarlos Song 		ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
3729d61c182SCarlos Song 				   val & ~FXOS8700_ACTIVE);
3739d61c182SCarlos Song 		if (ret)
3749d61c182SCarlos Song 			return ret;
3759d61c182SCarlos Song 	}
3769d61c182SCarlos Song 
37784e5ddd5SRobert Jones 	for (i = 0; i < scale_num; i++)
37884e5ddd5SRobert Jones 		if (fxos8700_accel_scale[i].uscale == uscale)
37984e5ddd5SRobert Jones 			break;
38084e5ddd5SRobert Jones 
38184e5ddd5SRobert Jones 	if (i == scale_num)
38284e5ddd5SRobert Jones 		return -EINVAL;
38384e5ddd5SRobert Jones 
3849d61c182SCarlos Song 	ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
38584e5ddd5SRobert Jones 			    fxos8700_accel_scale[i].bits);
3869d61c182SCarlos Song 	if (ret)
3879d61c182SCarlos Song 		return ret;
3889d61c182SCarlos Song 	return regmap_write(data->regmap, FXOS8700_CTRL_REG1,
3899d61c182SCarlos Song 				  active_mode);
39084e5ddd5SRobert Jones }
39184e5ddd5SRobert Jones 
fxos8700_get_scale(struct fxos8700_data * data,enum fxos8700_sensor t,int * uscale)39284e5ddd5SRobert Jones static int fxos8700_get_scale(struct fxos8700_data *data,
39384e5ddd5SRobert Jones 			      enum fxos8700_sensor t, int *uscale)
39484e5ddd5SRobert Jones {
39584e5ddd5SRobert Jones 	int i, ret, val;
39684e5ddd5SRobert Jones 	static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
39784e5ddd5SRobert Jones 
39884e5ddd5SRobert Jones 	if (t == FXOS8700_MAGN) {
399*2acd0313SCarlos Song 		*uscale = 1000; /* Magnetometer is locked at 0.001Gs */
40084e5ddd5SRobert Jones 		return 0;
40184e5ddd5SRobert Jones 	}
40284e5ddd5SRobert Jones 
40384e5ddd5SRobert Jones 	ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val);
40484e5ddd5SRobert Jones 	if (ret)
40584e5ddd5SRobert Jones 		return ret;
40684e5ddd5SRobert Jones 
40784e5ddd5SRobert Jones 	for (i = 0; i < scale_num; i++) {
40884e5ddd5SRobert Jones 		if (fxos8700_accel_scale[i].bits == (val & 0x3)) {
40984e5ddd5SRobert Jones 			*uscale = fxos8700_accel_scale[i].uscale;
41084e5ddd5SRobert Jones 			return 0;
41184e5ddd5SRobert Jones 		}
41284e5ddd5SRobert Jones 	}
41384e5ddd5SRobert Jones 
41484e5ddd5SRobert Jones 	return -EINVAL;
41584e5ddd5SRobert Jones }
41684e5ddd5SRobert Jones 
fxos8700_get_data(struct fxos8700_data * data,int chan_type,int axis,int * val)41784e5ddd5SRobert Jones static int fxos8700_get_data(struct fxos8700_data *data, int chan_type,
41884e5ddd5SRobert Jones 			     int axis, int *val)
41984e5ddd5SRobert Jones {
42084e5ddd5SRobert Jones 	u8 base, reg;
421a53f9458SCarlos Song 	s16 tmp;
42284e5ddd5SRobert Jones 	int ret;
42384e5ddd5SRobert Jones 
424c68b44bcSCarlos Song 	/*
425c68b44bcSCarlos Song 	 * Different register base addresses varies with channel types.
426c68b44bcSCarlos Song 	 * This bug hasn't been noticed before because using an enum is
427c68b44bcSCarlos Song 	 * really hard to read. Use an a switch statement to take over that.
428c68b44bcSCarlos Song 	 */
429c68b44bcSCarlos Song 	switch (chan_type) {
430c68b44bcSCarlos Song 	case IIO_ACCEL:
431c68b44bcSCarlos Song 		base = FXOS8700_OUT_X_MSB;
432c68b44bcSCarlos Song 		break;
433c68b44bcSCarlos Song 	case IIO_MAGN:
434c68b44bcSCarlos Song 		base = FXOS8700_M_OUT_X_MSB;
435c68b44bcSCarlos Song 		break;
436c68b44bcSCarlos Song 	default:
437c68b44bcSCarlos Song 		return -EINVAL;
438c68b44bcSCarlos Song 	}
43984e5ddd5SRobert Jones 
44084e5ddd5SRobert Jones 	/* Block read 6 bytes of device output registers to avoid data loss */
44184e5ddd5SRobert Jones 	ret = regmap_bulk_read(data->regmap, base, data->buf,
44237a94d86SCarlos Song 			       sizeof(data->buf));
44384e5ddd5SRobert Jones 	if (ret)
44484e5ddd5SRobert Jones 		return ret;
44584e5ddd5SRobert Jones 
44684e5ddd5SRobert Jones 	/* Convert axis to buffer index */
44784e5ddd5SRobert Jones 	reg = axis - IIO_MOD_X;
44884e5ddd5SRobert Jones 
449a53f9458SCarlos Song 	/*
450a53f9458SCarlos Song 	 * Convert to native endianness. The accel data and magn data
451a53f9458SCarlos Song 	 * are signed, so a forced type conversion is needed.
452a53f9458SCarlos Song 	 */
453a53f9458SCarlos Song 	tmp = be16_to_cpu(data->buf[reg]);
454a53f9458SCarlos Song 
455a53f9458SCarlos Song 	/*
456a53f9458SCarlos Song 	 * ACCEL output data registers contain the X-axis, Y-axis, and Z-axis
457a53f9458SCarlos Song 	 * 14-bit left-justified sample data and MAGN output data registers
458a53f9458SCarlos Song 	 * contain the X-axis, Y-axis, and Z-axis 16-bit sample data. Apply
459a53f9458SCarlos Song 	 * a signed 2 bits right shift to the readback raw data from ACCEL
460a53f9458SCarlos Song 	 * output data register and keep that from MAGN sensor as the origin.
461a53f9458SCarlos Song 	 * Value should be extended to 32 bit.
462a53f9458SCarlos Song 	 */
463a53f9458SCarlos Song 	switch (chan_type) {
464a53f9458SCarlos Song 	case IIO_ACCEL:
465a53f9458SCarlos Song 		tmp = tmp >> 2;
466a53f9458SCarlos Song 		break;
467a53f9458SCarlos Song 	case IIO_MAGN:
468a53f9458SCarlos Song 		/* Nothing to do */
469a53f9458SCarlos Song 		break;
470a53f9458SCarlos Song 	default:
471a53f9458SCarlos Song 		return -EINVAL;
472a53f9458SCarlos Song 	}
473a53f9458SCarlos Song 
47484e5ddd5SRobert Jones 	/* Convert to native endianness */
475a53f9458SCarlos Song 	*val = sign_extend32(tmp, 15);
47684e5ddd5SRobert Jones 
47784e5ddd5SRobert Jones 	return 0;
47884e5ddd5SRobert Jones }
47984e5ddd5SRobert Jones 
fxos8700_set_odr(struct fxos8700_data * data,enum fxos8700_sensor t,int odr,int uodr)48084e5ddd5SRobert Jones static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
48184e5ddd5SRobert Jones 			    int odr, int uodr)
48284e5ddd5SRobert Jones {
48384e5ddd5SRobert Jones 	int i, ret, val;
48484e5ddd5SRobert Jones 	bool active_mode;
48584e5ddd5SRobert Jones 	static const int odr_num = ARRAY_SIZE(fxos8700_odr);
48684e5ddd5SRobert Jones 
48784e5ddd5SRobert Jones 	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
48884e5ddd5SRobert Jones 	if (ret)
48984e5ddd5SRobert Jones 		return ret;
49084e5ddd5SRobert Jones 
49184e5ddd5SRobert Jones 	active_mode = val & FXOS8700_ACTIVE;
49284e5ddd5SRobert Jones 
49384e5ddd5SRobert Jones 	if (active_mode) {
49484e5ddd5SRobert Jones 		/*
49584e5ddd5SRobert Jones 		 * The device must be in standby mode to change any of the
49684e5ddd5SRobert Jones 		 * other fields within CTRL_REG1
49784e5ddd5SRobert Jones 		 */
49884e5ddd5SRobert Jones 		ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
49984e5ddd5SRobert Jones 				   val & ~FXOS8700_ACTIVE);
50084e5ddd5SRobert Jones 		if (ret)
50184e5ddd5SRobert Jones 			return ret;
50284e5ddd5SRobert Jones 	}
50384e5ddd5SRobert Jones 
50484e5ddd5SRobert Jones 	for (i = 0; i < odr_num; i++)
50584e5ddd5SRobert Jones 		if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr)
50684e5ddd5SRobert Jones 			break;
50784e5ddd5SRobert Jones 
50884e5ddd5SRobert Jones 	if (i >= odr_num)
50984e5ddd5SRobert Jones 		return -EINVAL;
51084e5ddd5SRobert Jones 
51178ad6864SCarlos Song 	val &= ~FXOS8700_CTRL_ODR_MSK;
51278ad6864SCarlos Song 	val |= FIELD_PREP(FXOS8700_CTRL_ODR_MSK, fxos8700_odr[i].bits) | FXOS8700_ACTIVE;
51378ad6864SCarlos Song 	return regmap_write(data->regmap, FXOS8700_CTRL_REG1, val);
51484e5ddd5SRobert Jones }
51584e5ddd5SRobert Jones 
fxos8700_get_odr(struct fxos8700_data * data,enum fxos8700_sensor t,int * odr,int * uodr)51684e5ddd5SRobert Jones static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
51784e5ddd5SRobert Jones 			    int *odr, int *uodr)
51884e5ddd5SRobert Jones {
51984e5ddd5SRobert Jones 	int i, val, ret;
52084e5ddd5SRobert Jones 	static const int odr_num = ARRAY_SIZE(fxos8700_odr);
52184e5ddd5SRobert Jones 
52284e5ddd5SRobert Jones 	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
52384e5ddd5SRobert Jones 	if (ret)
52484e5ddd5SRobert Jones 		return ret;
52584e5ddd5SRobert Jones 
52678ad6864SCarlos Song 	val = FIELD_GET(FXOS8700_CTRL_ODR_MSK, val);
52784e5ddd5SRobert Jones 
52884e5ddd5SRobert Jones 	for (i = 0; i < odr_num; i++)
52984e5ddd5SRobert Jones 		if (val == fxos8700_odr[i].bits)
53084e5ddd5SRobert Jones 			break;
53184e5ddd5SRobert Jones 
53284e5ddd5SRobert Jones 	if (i >= odr_num)
53384e5ddd5SRobert Jones 		return -EINVAL;
53484e5ddd5SRobert Jones 
53584e5ddd5SRobert Jones 	*odr = fxos8700_odr[i].odr;
53684e5ddd5SRobert Jones 	*uodr = fxos8700_odr[i].uodr;
53784e5ddd5SRobert Jones 
53884e5ddd5SRobert Jones 	return 0;
53984e5ddd5SRobert Jones }
54084e5ddd5SRobert Jones 
fxos8700_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)54184e5ddd5SRobert Jones static int fxos8700_read_raw(struct iio_dev *indio_dev,
54284e5ddd5SRobert Jones 			     struct iio_chan_spec const *chan,
54384e5ddd5SRobert Jones 			     int *val, int *val2, long mask)
54484e5ddd5SRobert Jones {
54584e5ddd5SRobert Jones 	int ret;
54684e5ddd5SRobert Jones 	struct fxos8700_data *data = iio_priv(indio_dev);
54784e5ddd5SRobert Jones 
54884e5ddd5SRobert Jones 	switch (mask) {
54984e5ddd5SRobert Jones 	case IIO_CHAN_INFO_RAW:
55084e5ddd5SRobert Jones 		ret = fxos8700_get_data(data, chan->type, chan->channel2, val);
55184e5ddd5SRobert Jones 		if (ret)
55284e5ddd5SRobert Jones 			return ret;
55384e5ddd5SRobert Jones 		return IIO_VAL_INT;
55484e5ddd5SRobert Jones 	case IIO_CHAN_INFO_SCALE:
55584e5ddd5SRobert Jones 		*val = 0;
55684e5ddd5SRobert Jones 		ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type),
55784e5ddd5SRobert Jones 					 val2);
55884e5ddd5SRobert Jones 		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
55984e5ddd5SRobert Jones 	case IIO_CHAN_INFO_SAMP_FREQ:
56084e5ddd5SRobert Jones 		ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type),
56184e5ddd5SRobert Jones 				       val, val2);
56284e5ddd5SRobert Jones 		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
56384e5ddd5SRobert Jones 	default:
56484e5ddd5SRobert Jones 		return -EINVAL;
56584e5ddd5SRobert Jones 	}
56684e5ddd5SRobert Jones }
56784e5ddd5SRobert Jones 
fxos8700_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)56884e5ddd5SRobert Jones static int fxos8700_write_raw(struct iio_dev *indio_dev,
56984e5ddd5SRobert Jones 			      struct iio_chan_spec const *chan,
57084e5ddd5SRobert Jones 			      int val, int val2, long mask)
57184e5ddd5SRobert Jones {
57284e5ddd5SRobert Jones 	struct fxos8700_data *data = iio_priv(indio_dev);
57384e5ddd5SRobert Jones 
57484e5ddd5SRobert Jones 	switch (mask) {
57584e5ddd5SRobert Jones 	case IIO_CHAN_INFO_SCALE:
57684e5ddd5SRobert Jones 		return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type),
57784e5ddd5SRobert Jones 					  val2);
57884e5ddd5SRobert Jones 	case IIO_CHAN_INFO_SAMP_FREQ:
57984e5ddd5SRobert Jones 		return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type),
58084e5ddd5SRobert Jones 					val, val2);
58184e5ddd5SRobert Jones 	default:
58284e5ddd5SRobert Jones 		return -EINVAL;
58384e5ddd5SRobert Jones 	}
58484e5ddd5SRobert Jones }
58584e5ddd5SRobert Jones 
58684e5ddd5SRobert Jones static IIO_CONST_ATTR(in_accel_sampling_frequency_available,
58784e5ddd5SRobert Jones 		      "1.5625 6.25 12.5 50 100 200 400 800");
58884e5ddd5SRobert Jones static IIO_CONST_ATTR(in_magn_sampling_frequency_available,
58984e5ddd5SRobert Jones 		      "1.5625 6.25 12.5 50 100 200 400 800");
59084e5ddd5SRobert Jones static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976");
591*2acd0313SCarlos Song static IIO_CONST_ATTR(in_magn_scale_available, "0.001000");
59284e5ddd5SRobert Jones 
59384e5ddd5SRobert Jones static struct attribute *fxos8700_attrs[] = {
59484e5ddd5SRobert Jones 	&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
59584e5ddd5SRobert Jones 	&iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr,
59684e5ddd5SRobert Jones 	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
59784e5ddd5SRobert Jones 	&iio_const_attr_in_magn_scale_available.dev_attr.attr,
59884e5ddd5SRobert Jones 	NULL,
59984e5ddd5SRobert Jones };
60084e5ddd5SRobert Jones 
60184e5ddd5SRobert Jones static const struct attribute_group fxos8700_attrs_group = {
60284e5ddd5SRobert Jones 	.attrs = fxos8700_attrs,
60384e5ddd5SRobert Jones };
60484e5ddd5SRobert Jones 
60584e5ddd5SRobert Jones static const struct iio_info fxos8700_info = {
60684e5ddd5SRobert Jones 	.read_raw = fxos8700_read_raw,
60784e5ddd5SRobert Jones 	.write_raw = fxos8700_write_raw,
60884e5ddd5SRobert Jones 	.attrs = &fxos8700_attrs_group,
60984e5ddd5SRobert Jones };
61084e5ddd5SRobert Jones 
fxos8700_chip_init(struct fxos8700_data * data,bool use_spi)61184e5ddd5SRobert Jones static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi)
61284e5ddd5SRobert Jones {
61384e5ddd5SRobert Jones 	int ret;
61484e5ddd5SRobert Jones 	unsigned int val;
61584e5ddd5SRobert Jones 	struct device *dev = regmap_get_device(data->regmap);
61684e5ddd5SRobert Jones 
61784e5ddd5SRobert Jones 	ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val);
61884e5ddd5SRobert Jones 	if (ret) {
61984e5ddd5SRobert Jones 		dev_err(dev, "Error reading chip id\n");
62084e5ddd5SRobert Jones 		return ret;
62184e5ddd5SRobert Jones 	}
62284e5ddd5SRobert Jones 	if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) {
62384e5ddd5SRobert Jones 		dev_err(dev, "Wrong chip id, got %x expected %x or %x\n",
62484e5ddd5SRobert Jones 			val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID);
62584e5ddd5SRobert Jones 		return -ENODEV;
62684e5ddd5SRobert Jones 	}
62784e5ddd5SRobert Jones 
62884e5ddd5SRobert Jones 	ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true);
62984e5ddd5SRobert Jones 	if (ret)
63084e5ddd5SRobert Jones 		return ret;
63184e5ddd5SRobert Jones 
63284e5ddd5SRobert Jones 	ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true);
63384e5ddd5SRobert Jones 	if (ret)
63484e5ddd5SRobert Jones 		return ret;
63584e5ddd5SRobert Jones 
63684e5ddd5SRobert Jones 	/*
63784e5ddd5SRobert Jones 	 * The device must be in standby mode to change any of the other fields
63884e5ddd5SRobert Jones 	 * within CTRL_REG1
63984e5ddd5SRobert Jones 	 */
64084e5ddd5SRobert Jones 	ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00);
64184e5ddd5SRobert Jones 	if (ret)
64284e5ddd5SRobert Jones 		return ret;
64384e5ddd5SRobert Jones 
64484e5ddd5SRobert Jones 	/* Set max oversample ratio (OSR) and both devices active */
64584e5ddd5SRobert Jones 	ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1,
64684e5ddd5SRobert Jones 			   FXOS8700_HMS_MASK | FXOS8700_OS_MASK);
64784e5ddd5SRobert Jones 	if (ret)
64884e5ddd5SRobert Jones 		return ret;
64984e5ddd5SRobert Jones 
65084e5ddd5SRobert Jones 	/* Disable and rst min/max measurements & threshold */
65184e5ddd5SRobert Jones 	ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2,
65284e5ddd5SRobert Jones 			   FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS |
65384e5ddd5SRobert Jones 			   FXOS8700_MAXMIN_DIS);
65484e5ddd5SRobert Jones 	if (ret)
65584e5ddd5SRobert Jones 		return ret;
65684e5ddd5SRobert Jones 
6579d61c182SCarlos Song 	/*
6589d61c182SCarlos Song 	 * Set max full-scale range (+/-8G) for ACCEL sensor in chip
6599d61c182SCarlos Song 	 * initialization then activate the device.
6609d61c182SCarlos Song 	 */
6619d61c182SCarlos Song 	ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
66284e5ddd5SRobert Jones 	if (ret)
66384e5ddd5SRobert Jones 		return ret;
66484e5ddd5SRobert Jones 
6659d61c182SCarlos Song 	/* Max ODR (800Hz individual or 400Hz hybrid), active mode */
666eb6d8f87SCarlos Song 	return regmap_update_bits(data->regmap, FXOS8700_CTRL_REG1,
667eb6d8f87SCarlos Song 				FXOS8700_CTRL_ODR_MSK | FXOS8700_ACTIVE,
668eb6d8f87SCarlos Song 				FIELD_PREP(FXOS8700_CTRL_ODR_MSK, FXOS8700_CTRL_ODR_MAX) |
669eb6d8f87SCarlos Song 				FXOS8700_ACTIVE);
67084e5ddd5SRobert Jones }
67184e5ddd5SRobert Jones 
fxos8700_chip_uninit(void * data)67284e5ddd5SRobert Jones static void fxos8700_chip_uninit(void *data)
67384e5ddd5SRobert Jones {
67484e5ddd5SRobert Jones 	struct fxos8700_data *fxos8700_data = data;
67584e5ddd5SRobert Jones 
67684e5ddd5SRobert Jones 	fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false);
67784e5ddd5SRobert Jones 	fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false);
67884e5ddd5SRobert Jones }
67984e5ddd5SRobert Jones 
fxos8700_core_probe(struct device * dev,struct regmap * regmap,const char * name,bool use_spi)68084e5ddd5SRobert Jones int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
68184e5ddd5SRobert Jones 			const char *name, bool use_spi)
68284e5ddd5SRobert Jones {
68384e5ddd5SRobert Jones 	struct iio_dev *indio_dev;
68484e5ddd5SRobert Jones 	struct fxos8700_data *data;
68584e5ddd5SRobert Jones 	int ret;
68684e5ddd5SRobert Jones 
68784e5ddd5SRobert Jones 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
68884e5ddd5SRobert Jones 	if (!indio_dev)
68984e5ddd5SRobert Jones 		return -ENOMEM;
69084e5ddd5SRobert Jones 
69184e5ddd5SRobert Jones 	data = iio_priv(indio_dev);
69284e5ddd5SRobert Jones 	dev_set_drvdata(dev, indio_dev);
69384e5ddd5SRobert Jones 	data->regmap = regmap;
69484e5ddd5SRobert Jones 
69584e5ddd5SRobert Jones 	ret = fxos8700_chip_init(data, use_spi);
69684e5ddd5SRobert Jones 	if (ret)
69784e5ddd5SRobert Jones 		return ret;
69884e5ddd5SRobert Jones 
69984e5ddd5SRobert Jones 	ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data);
70084e5ddd5SRobert Jones 	if (ret)
70184e5ddd5SRobert Jones 		return ret;
70284e5ddd5SRobert Jones 
70384e5ddd5SRobert Jones 	indio_dev->channels = fxos8700_channels;
70484e5ddd5SRobert Jones 	indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels);
70584e5ddd5SRobert Jones 	indio_dev->name = name ? name : "fxos8700";
70684e5ddd5SRobert Jones 	indio_dev->modes = INDIO_DIRECT_MODE;
70784e5ddd5SRobert Jones 	indio_dev->info = &fxos8700_info;
70884e5ddd5SRobert Jones 
70984e5ddd5SRobert Jones 	return devm_iio_device_register(dev, indio_dev);
71084e5ddd5SRobert Jones }
71184e5ddd5SRobert Jones EXPORT_SYMBOL_GPL(fxos8700_core_probe);
71284e5ddd5SRobert Jones 
71384e5ddd5SRobert Jones MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
71484e5ddd5SRobert Jones MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver");
71584e5ddd5SRobert Jones MODULE_LICENSE("GPL v2");
716