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