cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fxos8700_core.c (18179B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * FXOS8700 - NXP IMU (accelerometer plus magnetometer)
      4 *
      5 * IIO core driver for FXOS8700, with support for I2C/SPI busses
      6 *
      7 * TODO: Buffer, trigger, and IRQ support
      8 */
      9#include <linux/module.h>
     10#include <linux/regmap.h>
     11#include <linux/acpi.h>
     12#include <linux/bitops.h>
     13
     14#include <linux/iio/iio.h>
     15#include <linux/iio/sysfs.h>
     16
     17#include "fxos8700.h"
     18
     19/* Register Definitions */
     20#define FXOS8700_STATUS             0x00
     21#define FXOS8700_OUT_X_MSB          0x01
     22#define FXOS8700_OUT_X_LSB          0x02
     23#define FXOS8700_OUT_Y_MSB          0x03
     24#define FXOS8700_OUT_Y_LSB          0x04
     25#define FXOS8700_OUT_Z_MSB          0x05
     26#define FXOS8700_OUT_Z_LSB          0x06
     27#define FXOS8700_F_SETUP            0x09
     28#define FXOS8700_TRIG_CFG           0x0a
     29#define FXOS8700_SYSMOD             0x0b
     30#define FXOS8700_INT_SOURCE         0x0c
     31#define FXOS8700_WHO_AM_I           0x0d
     32#define FXOS8700_XYZ_DATA_CFG       0x0e
     33#define FXOS8700_HP_FILTER_CUTOFF   0x0f
     34#define FXOS8700_PL_STATUS          0x10
     35#define FXOS8700_PL_CFG             0x11
     36#define FXOS8700_PL_COUNT           0x12
     37#define FXOS8700_PL_BF_ZCOMP        0x13
     38#define FXOS8700_PL_THS_REG         0x14
     39#define FXOS8700_A_FFMT_CFG         0x15
     40#define FXOS8700_A_FFMT_SRC         0x16
     41#define FXOS8700_A_FFMT_THS         0x17
     42#define FXOS8700_A_FFMT_COUNT       0x18
     43#define FXOS8700_TRANSIENT_CFG      0x1d
     44#define FXOS8700_TRANSIENT_SRC      0x1e
     45#define FXOS8700_TRANSIENT_THS      0x1f
     46#define FXOS8700_TRANSIENT_COUNT    0x20
     47#define FXOS8700_PULSE_CFG          0x21
     48#define FXOS8700_PULSE_SRC          0x22
     49#define FXOS8700_PULSE_THSX         0x23
     50#define FXOS8700_PULSE_THSY         0x24
     51#define FXOS8700_PULSE_THSZ         0x25
     52#define FXOS8700_PULSE_TMLT         0x26
     53#define FXOS8700_PULSE_LTCY         0x27
     54#define FXOS8700_PULSE_WIND         0x28
     55#define FXOS8700_ASLP_COUNT         0x29
     56#define FXOS8700_CTRL_REG1          0x2a
     57#define FXOS8700_CTRL_REG2          0x2b
     58#define FXOS8700_CTRL_REG3          0x2c
     59#define FXOS8700_CTRL_REG4          0x2d
     60#define FXOS8700_CTRL_REG5          0x2e
     61#define FXOS8700_OFF_X              0x2f
     62#define FXOS8700_OFF_Y              0x30
     63#define FXOS8700_OFF_Z              0x31
     64#define FXOS8700_M_DR_STATUS        0x32
     65#define FXOS8700_M_OUT_X_MSB        0x33
     66#define FXOS8700_M_OUT_X_LSB        0x34
     67#define FXOS8700_M_OUT_Y_MSB        0x35
     68#define FXOS8700_M_OUT_Y_LSB        0x36
     69#define FXOS8700_M_OUT_Z_MSB        0x37
     70#define FXOS8700_M_OUT_Z_LSB        0x38
     71#define FXOS8700_CMP_X_MSB          0x39
     72#define FXOS8700_CMP_X_LSB          0x3a
     73#define FXOS8700_CMP_Y_MSB          0x3b
     74#define FXOS8700_CMP_Y_LSB          0x3c
     75#define FXOS8700_CMP_Z_MSB          0x3d
     76#define FXOS8700_CMP_Z_LSB          0x3e
     77#define FXOS8700_M_OFF_X_MSB        0x3f
     78#define FXOS8700_M_OFF_X_LSB        0x40
     79#define FXOS8700_M_OFF_Y_MSB        0x41
     80#define FXOS8700_M_OFF_Y_LSB        0x42
     81#define FXOS8700_M_OFF_Z_MSB        0x43
     82#define FXOS8700_M_OFF_Z_LSB        0x44
     83#define FXOS8700_MAX_X_MSB          0x45
     84#define FXOS8700_MAX_X_LSB          0x46
     85#define FXOS8700_MAX_Y_MSB          0x47
     86#define FXOS8700_MAX_Y_LSB          0x48
     87#define FXOS8700_MAX_Z_MSB          0x49
     88#define FXOS8700_MAX_Z_LSB          0x4a
     89#define FXOS8700_MIN_X_MSB          0x4b
     90#define FXOS8700_MIN_X_LSB          0x4c
     91#define FXOS8700_MIN_Y_MSB          0x4d
     92#define FXOS8700_MIN_Y_LSB          0x4e
     93#define FXOS8700_MIN_Z_MSB          0x4f
     94#define FXOS8700_MIN_Z_LSB          0x50
     95#define FXOS8700_TEMP               0x51
     96#define FXOS8700_M_THS_CFG          0x52
     97#define FXOS8700_M_THS_SRC          0x53
     98#define FXOS8700_M_THS_X_MSB        0x54
     99#define FXOS8700_M_THS_X_LSB        0x55
    100#define FXOS8700_M_THS_Y_MSB        0x56
    101#define FXOS8700_M_THS_Y_LSB        0x57
    102#define FXOS8700_M_THS_Z_MSB        0x58
    103#define FXOS8700_M_THS_Z_LSB        0x59
    104#define FXOS8700_M_THS_COUNT        0x5a
    105#define FXOS8700_M_CTRL_REG1        0x5b
    106#define FXOS8700_M_CTRL_REG2        0x5c
    107#define FXOS8700_M_CTRL_REG3        0x5d
    108#define FXOS8700_M_INT_SRC          0x5e
    109#define FXOS8700_A_VECM_CFG         0x5f
    110#define FXOS8700_A_VECM_THS_MSB     0x60
    111#define FXOS8700_A_VECM_THS_LSB     0x61
    112#define FXOS8700_A_VECM_CNT         0x62
    113#define FXOS8700_A_VECM_INITX_MSB   0x63
    114#define FXOS8700_A_VECM_INITX_LSB   0x64
    115#define FXOS8700_A_VECM_INITY_MSB   0x65
    116#define FXOS8700_A_VECM_INITY_LSB   0x66
    117#define FXOS8700_A_VECM_INITZ_MSB   0x67
    118#define FXOS8700_A_VECM_INITZ_LSB   0x68
    119#define FXOS8700_M_VECM_CFG         0x69
    120#define FXOS8700_M_VECM_THS_MSB     0x6a
    121#define FXOS8700_M_VECM_THS_LSB     0x6b
    122#define FXOS8700_M_VECM_CNT         0x6c
    123#define FXOS8700_M_VECM_INITX_MSB   0x6d
    124#define FXOS8700_M_VECM_INITX_LSB   0x6e
    125#define FXOS8700_M_VECM_INITY_MSB   0x6f
    126#define FXOS8700_M_VECM_INITY_LSB   0x70
    127#define FXOS8700_M_VECM_INITZ_MSB   0x71
    128#define FXOS8700_M_VECM_INITZ_LSB   0x72
    129#define FXOS8700_A_FFMT_THS_X_MSB   0x73
    130#define FXOS8700_A_FFMT_THS_X_LSB   0x74
    131#define FXOS8700_A_FFMT_THS_Y_MSB   0x75
    132#define FXOS8700_A_FFMT_THS_Y_LSB   0x76
    133#define FXOS8700_A_FFMT_THS_Z_MSB   0x77
    134#define FXOS8700_A_FFMT_THS_Z_LSB   0x78
    135#define FXOS8700_A_TRAN_INIT_MSB    0x79
    136#define FXOS8700_A_TRAN_INIT_LSB_X  0x7a
    137#define FXOS8700_A_TRAN_INIT_LSB_Y  0x7b
    138#define FXOS8700_A_TRAN_INIT_LSB_Z  0x7d
    139#define FXOS8700_TM_NVM_LOCK        0x7e
    140#define FXOS8700_NVM_DATA0_35       0x80
    141#define FXOS8700_NVM_DATA_BNK3      0xa4
    142#define FXOS8700_NVM_DATA_BNK2      0xa5
    143#define FXOS8700_NVM_DATA_BNK1      0xa6
    144#define FXOS8700_NVM_DATA_BNK0      0xa7
    145
    146/* Bit definitions for FXOS8700_CTRL_REG1 */
    147#define FXOS8700_CTRL_ODR_MSK       0x38
    148#define FXOS8700_CTRL_ODR_MAX       0x00
    149#define FXOS8700_CTRL_ODR_MIN       GENMASK(4, 3)
    150
    151/* Bit definitions for FXOS8700_M_CTRL_REG1 */
    152#define FXOS8700_HMS_MASK           GENMASK(1, 0)
    153#define FXOS8700_OS_MASK            GENMASK(4, 2)
    154
    155/* Bit definitions for FXOS8700_M_CTRL_REG2 */
    156#define FXOS8700_MAXMIN_RST         BIT(2)
    157#define FXOS8700_MAXMIN_DIS_THS     BIT(3)
    158#define FXOS8700_MAXMIN_DIS         BIT(4)
    159
    160#define FXOS8700_ACTIVE             0x01
    161#define FXOS8700_ACTIVE_MIN_USLEEP  4000 /* from table 6 in datasheet */
    162
    163#define FXOS8700_DEVICE_ID          0xC7
    164#define FXOS8700_PRE_DEVICE_ID      0xC4
    165#define FXOS8700_DATA_BUF_SIZE      3
    166
    167struct fxos8700_data {
    168	struct regmap *regmap;
    169	struct iio_trigger *trig;
    170	__be16 buf[FXOS8700_DATA_BUF_SIZE] ____cacheline_aligned;
    171};
    172
    173/* Regmap info */
    174static const struct regmap_range read_range[] = {
    175	{
    176		.range_min = FXOS8700_STATUS,
    177		.range_max = FXOS8700_A_FFMT_COUNT,
    178	}, {
    179		.range_min = FXOS8700_TRANSIENT_CFG,
    180		.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
    181	},
    182};
    183
    184static const struct regmap_range write_range[] = {
    185	{
    186		.range_min = FXOS8700_F_SETUP,
    187		.range_max = FXOS8700_TRIG_CFG,
    188	}, {
    189		.range_min = FXOS8700_XYZ_DATA_CFG,
    190		.range_max = FXOS8700_HP_FILTER_CUTOFF,
    191	}, {
    192		.range_min = FXOS8700_PL_CFG,
    193		.range_max = FXOS8700_A_FFMT_CFG,
    194	}, {
    195		.range_min = FXOS8700_A_FFMT_THS,
    196		.range_max = FXOS8700_TRANSIENT_CFG,
    197	}, {
    198		.range_min = FXOS8700_TRANSIENT_THS,
    199		.range_max = FXOS8700_PULSE_CFG,
    200	}, {
    201		.range_min = FXOS8700_PULSE_THSX,
    202		.range_max = FXOS8700_OFF_Z,
    203	}, {
    204		.range_min = FXOS8700_M_OFF_X_MSB,
    205		.range_max = FXOS8700_M_OFF_Z_LSB,
    206	}, {
    207		.range_min = FXOS8700_M_THS_CFG,
    208		.range_max = FXOS8700_M_THS_CFG,
    209	}, {
    210		.range_min = FXOS8700_M_THS_X_MSB,
    211		.range_max = FXOS8700_M_CTRL_REG3,
    212	}, {
    213		.range_min = FXOS8700_A_VECM_CFG,
    214		.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
    215	},
    216};
    217
    218static const struct regmap_access_table driver_read_table = {
    219	.yes_ranges =   read_range,
    220	.n_yes_ranges = ARRAY_SIZE(read_range),
    221};
    222
    223static const struct regmap_access_table driver_write_table = {
    224	.yes_ranges =   write_range,
    225	.n_yes_ranges = ARRAY_SIZE(write_range),
    226};
    227
    228const struct regmap_config fxos8700_regmap_config = {
    229	.reg_bits = 8,
    230	.val_bits = 8,
    231	.max_register = FXOS8700_NVM_DATA_BNK0,
    232	.rd_table = &driver_read_table,
    233	.wr_table = &driver_write_table,
    234};
    235EXPORT_SYMBOL(fxos8700_regmap_config);
    236
    237#define FXOS8700_CHANNEL(_type, _axis) {			\
    238	.type = _type,						\
    239	.modified = 1,						\
    240	.channel2 = IIO_MOD_##_axis,				\
    241	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
    242	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |  \
    243		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
    244}
    245
    246enum fxos8700_accel_scale_bits {
    247	MODE_2G = 0,
    248	MODE_4G,
    249	MODE_8G,
    250};
    251
    252/* scan indexes follow DATA register order */
    253enum fxos8700_scan_axis {
    254	FXOS8700_SCAN_ACCEL_X = 0,
    255	FXOS8700_SCAN_ACCEL_Y,
    256	FXOS8700_SCAN_ACCEL_Z,
    257	FXOS8700_SCAN_MAGN_X,
    258	FXOS8700_SCAN_MAGN_Y,
    259	FXOS8700_SCAN_MAGN_Z,
    260	FXOS8700_SCAN_RHALL,
    261	FXOS8700_SCAN_TIMESTAMP,
    262};
    263
    264enum fxos8700_sensor {
    265	FXOS8700_ACCEL	= 0,
    266	FXOS8700_MAGN,
    267	FXOS8700_NUM_SENSORS /* must be last */
    268};
    269
    270enum fxos8700_int_pin {
    271	FXOS8700_PIN_INT1,
    272	FXOS8700_PIN_INT2
    273};
    274
    275struct fxos8700_scale {
    276	u8 bits;
    277	int uscale;
    278};
    279
    280struct fxos8700_odr {
    281	u8 bits;
    282	int odr;
    283	int uodr;
    284};
    285
    286static const struct fxos8700_scale fxos8700_accel_scale[] = {
    287	{ MODE_2G, 244},
    288	{ MODE_4G, 488},
    289	{ MODE_8G, 976},
    290};
    291
    292/*
    293 * Accellerometer and magnetometer have the same ODR options, set in the
    294 * CTRL_REG1 register. ODR is halved when using both sensors at once in
    295 * hybrid mode.
    296 */
    297static const struct fxos8700_odr fxos8700_odr[] = {
    298	{0x00, 800, 0},
    299	{0x01, 400, 0},
    300	{0x02, 200, 0},
    301	{0x03, 100, 0},
    302	{0x04, 50, 0},
    303	{0x05, 12, 500000},
    304	{0x06, 6, 250000},
    305	{0x07, 1, 562500},
    306};
    307
    308static const struct iio_chan_spec fxos8700_channels[] = {
    309	FXOS8700_CHANNEL(IIO_ACCEL, X),
    310	FXOS8700_CHANNEL(IIO_ACCEL, Y),
    311	FXOS8700_CHANNEL(IIO_ACCEL, Z),
    312	FXOS8700_CHANNEL(IIO_MAGN, X),
    313	FXOS8700_CHANNEL(IIO_MAGN, Y),
    314	FXOS8700_CHANNEL(IIO_MAGN, Z),
    315	IIO_CHAN_SOFT_TIMESTAMP(FXOS8700_SCAN_TIMESTAMP),
    316};
    317
    318static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type)
    319{
    320	switch (iio_type) {
    321	case IIO_ACCEL:
    322		return FXOS8700_ACCEL;
    323	case IIO_ANGL_VEL:
    324		return FXOS8700_MAGN;
    325	default:
    326		return -EINVAL;
    327	}
    328}
    329
    330static int fxos8700_set_active_mode(struct fxos8700_data *data,
    331				    enum fxos8700_sensor t, bool mode)
    332{
    333	int ret;
    334
    335	ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, mode);
    336	if (ret)
    337		return ret;
    338
    339	usleep_range(FXOS8700_ACTIVE_MIN_USLEEP,
    340		     FXOS8700_ACTIVE_MIN_USLEEP + 1000);
    341
    342	return 0;
    343}
    344
    345static int fxos8700_set_scale(struct fxos8700_data *data,
    346			      enum fxos8700_sensor t, int uscale)
    347{
    348	int i;
    349	static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
    350	struct device *dev = regmap_get_device(data->regmap);
    351
    352	if (t == FXOS8700_MAGN) {
    353		dev_err(dev, "Magnetometer scale is locked at 1200uT\n");
    354		return -EINVAL;
    355	}
    356
    357	for (i = 0; i < scale_num; i++)
    358		if (fxos8700_accel_scale[i].uscale == uscale)
    359			break;
    360
    361	if (i == scale_num)
    362		return -EINVAL;
    363
    364	return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
    365			    fxos8700_accel_scale[i].bits);
    366}
    367
    368static int fxos8700_get_scale(struct fxos8700_data *data,
    369			      enum fxos8700_sensor t, int *uscale)
    370{
    371	int i, ret, val;
    372	static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
    373
    374	if (t == FXOS8700_MAGN) {
    375		*uscale = 1200; /* Magnetometer is locked at 1200uT */
    376		return 0;
    377	}
    378
    379	ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val);
    380	if (ret)
    381		return ret;
    382
    383	for (i = 0; i < scale_num; i++) {
    384		if (fxos8700_accel_scale[i].bits == (val & 0x3)) {
    385			*uscale = fxos8700_accel_scale[i].uscale;
    386			return 0;
    387		}
    388	}
    389
    390	return -EINVAL;
    391}
    392
    393static int fxos8700_get_data(struct fxos8700_data *data, int chan_type,
    394			     int axis, int *val)
    395{
    396	u8 base, reg;
    397	int ret;
    398	enum fxos8700_sensor type = fxos8700_to_sensor(chan_type);
    399
    400	base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB;
    401
    402	/* Block read 6 bytes of device output registers to avoid data loss */
    403	ret = regmap_bulk_read(data->regmap, base, data->buf,
    404			       FXOS8700_DATA_BUF_SIZE);
    405	if (ret)
    406		return ret;
    407
    408	/* Convert axis to buffer index */
    409	reg = axis - IIO_MOD_X;
    410
    411	/* Convert to native endianness */
    412	*val = sign_extend32(be16_to_cpu(data->buf[reg]), 15);
    413
    414	return 0;
    415}
    416
    417static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
    418			    int odr, int uodr)
    419{
    420	int i, ret, val;
    421	bool active_mode;
    422	static const int odr_num = ARRAY_SIZE(fxos8700_odr);
    423
    424	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
    425	if (ret)
    426		return ret;
    427
    428	active_mode = val & FXOS8700_ACTIVE;
    429
    430	if (active_mode) {
    431		/*
    432		 * The device must be in standby mode to change any of the
    433		 * other fields within CTRL_REG1
    434		 */
    435		ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
    436				   val & ~FXOS8700_ACTIVE);
    437		if (ret)
    438			return ret;
    439	}
    440
    441	for (i = 0; i < odr_num; i++)
    442		if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr)
    443			break;
    444
    445	if (i >= odr_num)
    446		return -EINVAL;
    447
    448	return regmap_update_bits(data->regmap,
    449				  FXOS8700_CTRL_REG1,
    450				  FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE,
    451				  fxos8700_odr[i].bits << 3 | active_mode);
    452}
    453
    454static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
    455			    int *odr, int *uodr)
    456{
    457	int i, val, ret;
    458	static const int odr_num = ARRAY_SIZE(fxos8700_odr);
    459
    460	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
    461	if (ret)
    462		return ret;
    463
    464	val &= FXOS8700_CTRL_ODR_MSK;
    465
    466	for (i = 0; i < odr_num; i++)
    467		if (val == fxos8700_odr[i].bits)
    468			break;
    469
    470	if (i >= odr_num)
    471		return -EINVAL;
    472
    473	*odr = fxos8700_odr[i].odr;
    474	*uodr = fxos8700_odr[i].uodr;
    475
    476	return 0;
    477}
    478
    479static int fxos8700_read_raw(struct iio_dev *indio_dev,
    480			     struct iio_chan_spec const *chan,
    481			     int *val, int *val2, long mask)
    482{
    483	int ret;
    484	struct fxos8700_data *data = iio_priv(indio_dev);
    485
    486	switch (mask) {
    487	case IIO_CHAN_INFO_RAW:
    488		ret = fxos8700_get_data(data, chan->type, chan->channel2, val);
    489		if (ret)
    490			return ret;
    491		return IIO_VAL_INT;
    492	case IIO_CHAN_INFO_SCALE:
    493		*val = 0;
    494		ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type),
    495					 val2);
    496		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
    497	case IIO_CHAN_INFO_SAMP_FREQ:
    498		ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type),
    499				       val, val2);
    500		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
    501	default:
    502		return -EINVAL;
    503	}
    504}
    505
    506static int fxos8700_write_raw(struct iio_dev *indio_dev,
    507			      struct iio_chan_spec const *chan,
    508			      int val, int val2, long mask)
    509{
    510	struct fxos8700_data *data = iio_priv(indio_dev);
    511
    512	switch (mask) {
    513	case IIO_CHAN_INFO_SCALE:
    514		return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type),
    515					  val2);
    516	case IIO_CHAN_INFO_SAMP_FREQ:
    517		return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type),
    518					val, val2);
    519	default:
    520		return -EINVAL;
    521	}
    522}
    523
    524static IIO_CONST_ATTR(in_accel_sampling_frequency_available,
    525		      "1.5625 6.25 12.5 50 100 200 400 800");
    526static IIO_CONST_ATTR(in_magn_sampling_frequency_available,
    527		      "1.5625 6.25 12.5 50 100 200 400 800");
    528static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976");
    529static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200");
    530
    531static struct attribute *fxos8700_attrs[] = {
    532	&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
    533	&iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr,
    534	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
    535	&iio_const_attr_in_magn_scale_available.dev_attr.attr,
    536	NULL,
    537};
    538
    539static const struct attribute_group fxos8700_attrs_group = {
    540	.attrs = fxos8700_attrs,
    541};
    542
    543static const struct iio_info fxos8700_info = {
    544	.read_raw = fxos8700_read_raw,
    545	.write_raw = fxos8700_write_raw,
    546	.attrs = &fxos8700_attrs_group,
    547};
    548
    549static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi)
    550{
    551	int ret;
    552	unsigned int val;
    553	struct device *dev = regmap_get_device(data->regmap);
    554
    555	ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val);
    556	if (ret) {
    557		dev_err(dev, "Error reading chip id\n");
    558		return ret;
    559	}
    560	if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) {
    561		dev_err(dev, "Wrong chip id, got %x expected %x or %x\n",
    562			val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID);
    563		return -ENODEV;
    564	}
    565
    566	ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true);
    567	if (ret)
    568		return ret;
    569
    570	ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true);
    571	if (ret)
    572		return ret;
    573
    574	/*
    575	 * The device must be in standby mode to change any of the other fields
    576	 * within CTRL_REG1
    577	 */
    578	ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00);
    579	if (ret)
    580		return ret;
    581
    582	/* Set max oversample ratio (OSR) and both devices active */
    583	ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1,
    584			   FXOS8700_HMS_MASK | FXOS8700_OS_MASK);
    585	if (ret)
    586		return ret;
    587
    588	/* Disable and rst min/max measurements & threshold */
    589	ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2,
    590			   FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS |
    591			   FXOS8700_MAXMIN_DIS);
    592	if (ret)
    593		return ret;
    594
    595	/* Max ODR (800Hz individual or 400Hz hybrid), active mode */
    596	ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
    597			   FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE);
    598	if (ret)
    599		return ret;
    600
    601	/* Set for max full-scale range (+/-8G) */
    602	return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
    603}
    604
    605static void fxos8700_chip_uninit(void *data)
    606{
    607	struct fxos8700_data *fxos8700_data = data;
    608
    609	fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false);
    610	fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false);
    611}
    612
    613int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
    614			const char *name, bool use_spi)
    615{
    616	struct iio_dev *indio_dev;
    617	struct fxos8700_data *data;
    618	int ret;
    619
    620	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
    621	if (!indio_dev)
    622		return -ENOMEM;
    623
    624	data = iio_priv(indio_dev);
    625	dev_set_drvdata(dev, indio_dev);
    626	data->regmap = regmap;
    627
    628	ret = fxos8700_chip_init(data, use_spi);
    629	if (ret)
    630		return ret;
    631
    632	ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data);
    633	if (ret)
    634		return ret;
    635
    636	indio_dev->channels = fxos8700_channels;
    637	indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels);
    638	indio_dev->name = name ? name : "fxos8700";
    639	indio_dev->modes = INDIO_DIRECT_MODE;
    640	indio_dev->info = &fxos8700_info;
    641
    642	return devm_iio_device_register(dev, indio_dev);
    643}
    644EXPORT_SYMBOL_GPL(fxos8700_core_probe);
    645
    646MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
    647MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver");
    648MODULE_LICENSE("GPL v2");