brintos

brintos / linux-shallow public Read only

0
0
Text · 19.5 KiB · 6d189c4 Raw
716 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * FXOS8700 - NXP IMU (accelerometer plus magnetometer)4 *5 * IIO core driver for FXOS8700, with support for I2C/SPI busses6 *7 * TODO: Buffer, trigger, and IRQ support8 */9#include <linux/module.h>10#include <linux/regmap.h>11#include <linux/acpi.h>12#include <linux/bitops.h>13#include <linux/bitfield.h>14 15#include <linux/iio/iio.h>16#include <linux/iio/sysfs.h>17 18#include "fxos8700.h"19 20/* Register Definitions */21#define FXOS8700_STATUS             0x0022#define FXOS8700_OUT_X_MSB          0x0123#define FXOS8700_OUT_X_LSB          0x0224#define FXOS8700_OUT_Y_MSB          0x0325#define FXOS8700_OUT_Y_LSB          0x0426#define FXOS8700_OUT_Z_MSB          0x0527#define FXOS8700_OUT_Z_LSB          0x0628#define FXOS8700_F_SETUP            0x0929#define FXOS8700_TRIG_CFG           0x0a30#define FXOS8700_SYSMOD             0x0b31#define FXOS8700_INT_SOURCE         0x0c32#define FXOS8700_WHO_AM_I           0x0d33#define FXOS8700_XYZ_DATA_CFG       0x0e34#define FXOS8700_HP_FILTER_CUTOFF   0x0f35#define FXOS8700_PL_STATUS          0x1036#define FXOS8700_PL_CFG             0x1137#define FXOS8700_PL_COUNT           0x1238#define FXOS8700_PL_BF_ZCOMP        0x1339#define FXOS8700_PL_THS_REG         0x1440#define FXOS8700_A_FFMT_CFG         0x1541#define FXOS8700_A_FFMT_SRC         0x1642#define FXOS8700_A_FFMT_THS         0x1743#define FXOS8700_A_FFMT_COUNT       0x1844#define FXOS8700_TRANSIENT_CFG      0x1d45#define FXOS8700_TRANSIENT_SRC      0x1e46#define FXOS8700_TRANSIENT_THS      0x1f47#define FXOS8700_TRANSIENT_COUNT    0x2048#define FXOS8700_PULSE_CFG          0x2149#define FXOS8700_PULSE_SRC          0x2250#define FXOS8700_PULSE_THSX         0x2351#define FXOS8700_PULSE_THSY         0x2452#define FXOS8700_PULSE_THSZ         0x2553#define FXOS8700_PULSE_TMLT         0x2654#define FXOS8700_PULSE_LTCY         0x2755#define FXOS8700_PULSE_WIND         0x2856#define FXOS8700_ASLP_COUNT         0x2957#define FXOS8700_CTRL_REG1          0x2a58#define FXOS8700_CTRL_REG2          0x2b59#define FXOS8700_CTRL_REG3          0x2c60#define FXOS8700_CTRL_REG4          0x2d61#define FXOS8700_CTRL_REG5          0x2e62#define FXOS8700_OFF_X              0x2f63#define FXOS8700_OFF_Y              0x3064#define FXOS8700_OFF_Z              0x3165#define FXOS8700_M_DR_STATUS        0x3266#define FXOS8700_M_OUT_X_MSB        0x3367#define FXOS8700_M_OUT_X_LSB        0x3468#define FXOS8700_M_OUT_Y_MSB        0x3569#define FXOS8700_M_OUT_Y_LSB        0x3670#define FXOS8700_M_OUT_Z_MSB        0x3771#define FXOS8700_M_OUT_Z_LSB        0x3872#define FXOS8700_CMP_X_MSB          0x3973#define FXOS8700_CMP_X_LSB          0x3a74#define FXOS8700_CMP_Y_MSB          0x3b75#define FXOS8700_CMP_Y_LSB          0x3c76#define FXOS8700_CMP_Z_MSB          0x3d77#define FXOS8700_CMP_Z_LSB          0x3e78#define FXOS8700_M_OFF_X_MSB        0x3f79#define FXOS8700_M_OFF_X_LSB        0x4080#define FXOS8700_M_OFF_Y_MSB        0x4181#define FXOS8700_M_OFF_Y_LSB        0x4282#define FXOS8700_M_OFF_Z_MSB        0x4383#define FXOS8700_M_OFF_Z_LSB        0x4484#define FXOS8700_MAX_X_MSB          0x4585#define FXOS8700_MAX_X_LSB          0x4686#define FXOS8700_MAX_Y_MSB          0x4787#define FXOS8700_MAX_Y_LSB          0x4888#define FXOS8700_MAX_Z_MSB          0x4989#define FXOS8700_MAX_Z_LSB          0x4a90#define FXOS8700_MIN_X_MSB          0x4b91#define FXOS8700_MIN_X_LSB          0x4c92#define FXOS8700_MIN_Y_MSB          0x4d93#define FXOS8700_MIN_Y_LSB          0x4e94#define FXOS8700_MIN_Z_MSB          0x4f95#define FXOS8700_MIN_Z_LSB          0x5096#define FXOS8700_TEMP               0x5197#define FXOS8700_M_THS_CFG          0x5298#define FXOS8700_M_THS_SRC          0x5399#define FXOS8700_M_THS_X_MSB        0x54100#define FXOS8700_M_THS_X_LSB        0x55101#define FXOS8700_M_THS_Y_MSB        0x56102#define FXOS8700_M_THS_Y_LSB        0x57103#define FXOS8700_M_THS_Z_MSB        0x58104#define FXOS8700_M_THS_Z_LSB        0x59105#define FXOS8700_M_THS_COUNT        0x5a106#define FXOS8700_M_CTRL_REG1        0x5b107#define FXOS8700_M_CTRL_REG2        0x5c108#define FXOS8700_M_CTRL_REG3        0x5d109#define FXOS8700_M_INT_SRC          0x5e110#define FXOS8700_A_VECM_CFG         0x5f111#define FXOS8700_A_VECM_THS_MSB     0x60112#define FXOS8700_A_VECM_THS_LSB     0x61113#define FXOS8700_A_VECM_CNT         0x62114#define FXOS8700_A_VECM_INITX_MSB   0x63115#define FXOS8700_A_VECM_INITX_LSB   0x64116#define FXOS8700_A_VECM_INITY_MSB   0x65117#define FXOS8700_A_VECM_INITY_LSB   0x66118#define FXOS8700_A_VECM_INITZ_MSB   0x67119#define FXOS8700_A_VECM_INITZ_LSB   0x68120#define FXOS8700_M_VECM_CFG         0x69121#define FXOS8700_M_VECM_THS_MSB     0x6a122#define FXOS8700_M_VECM_THS_LSB     0x6b123#define FXOS8700_M_VECM_CNT         0x6c124#define FXOS8700_M_VECM_INITX_MSB   0x6d125#define FXOS8700_M_VECM_INITX_LSB   0x6e126#define FXOS8700_M_VECM_INITY_MSB   0x6f127#define FXOS8700_M_VECM_INITY_LSB   0x70128#define FXOS8700_M_VECM_INITZ_MSB   0x71129#define FXOS8700_M_VECM_INITZ_LSB   0x72130#define FXOS8700_A_FFMT_THS_X_MSB   0x73131#define FXOS8700_A_FFMT_THS_X_LSB   0x74132#define FXOS8700_A_FFMT_THS_Y_MSB   0x75133#define FXOS8700_A_FFMT_THS_Y_LSB   0x76134#define FXOS8700_A_FFMT_THS_Z_MSB   0x77135#define FXOS8700_A_FFMT_THS_Z_LSB   0x78136#define FXOS8700_A_TRAN_INIT_MSB    0x79137#define FXOS8700_A_TRAN_INIT_LSB_X  0x7a138#define FXOS8700_A_TRAN_INIT_LSB_Y  0x7b139#define FXOS8700_A_TRAN_INIT_LSB_Z  0x7d140#define FXOS8700_TM_NVM_LOCK        0x7e141#define FXOS8700_NVM_DATA0_35       0x80142#define FXOS8700_NVM_DATA_BNK3      0xa4143#define FXOS8700_NVM_DATA_BNK2      0xa5144#define FXOS8700_NVM_DATA_BNK1      0xa6145#define FXOS8700_NVM_DATA_BNK0      0xa7146 147/* Bit definitions for FXOS8700_CTRL_REG1 */148#define FXOS8700_CTRL_ODR_MAX       0x00149#define FXOS8700_CTRL_ODR_MSK       GENMASK(5, 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             0x01161#define FXOS8700_ACTIVE_MIN_USLEEP  4000 /* from table 6 in datasheet */162 163#define FXOS8700_DEVICE_ID          0xC7164#define FXOS8700_PRE_DEVICE_ID      0xC4165#define FXOS8700_DATA_BUF_SIZE      3166 167struct fxos8700_data {168	struct regmap *regmap;169	struct iio_trigger *trig;170	__be16 buf[FXOS8700_DATA_BUF_SIZE] __aligned(IIO_DMA_MINALIGN);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_INT2273};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 the294 * CTRL_REG1 register. ODR is halved when using both sensors at once in295 * 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_MAGN: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, ret, val;349	bool active_mode;350	static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);351	struct device *dev = regmap_get_device(data->regmap);352 353	if (t == FXOS8700_MAGN) {354		dev_err(dev, "Magnetometer scale is locked at 0.001Gs\n");355		return -EINVAL;356	}357 358	/*359	 * When device is in active mode, it failed to set an ACCEL360	 * full-scale range(2g/4g/8g) in FXOS8700_XYZ_DATA_CFG.361	 * This is not align with the datasheet, but it is a fxos8700362	 * chip behavier. Set the device in standby mode before setting363	 * an ACCEL full-scale range.364	 */365	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);366	if (ret)367		return ret;368 369	active_mode = val & FXOS8700_ACTIVE;370	if (active_mode) {371		ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,372				   val & ~FXOS8700_ACTIVE);373		if (ret)374			return ret;375	}376 377	for (i = 0; i < scale_num; i++)378		if (fxos8700_accel_scale[i].uscale == uscale)379			break;380 381	if (i == scale_num)382		return -EINVAL;383 384	ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,385			    fxos8700_accel_scale[i].bits);386	if (ret)387		return ret;388	return regmap_write(data->regmap, FXOS8700_CTRL_REG1,389				  active_mode);390}391 392static int fxos8700_get_scale(struct fxos8700_data *data,393			      enum fxos8700_sensor t, int *uscale)394{395	int i, ret, val;396	static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);397 398	if (t == FXOS8700_MAGN) {399		*uscale = 1000; /* Magnetometer is locked at 0.001Gs */400		return 0;401	}402 403	ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val);404	if (ret)405		return ret;406 407	for (i = 0; i < scale_num; i++) {408		if (fxos8700_accel_scale[i].bits == (val & 0x3)) {409			*uscale = fxos8700_accel_scale[i].uscale;410			return 0;411		}412	}413 414	return -EINVAL;415}416 417static int fxos8700_get_data(struct fxos8700_data *data, int chan_type,418			     int axis, int *val)419{420	u8 base, reg;421	s16 tmp;422	int ret;423 424	/*425	 * Different register base addresses varies with channel types.426	 * This bug hasn't been noticed before because using an enum is427	 * really hard to read. Use an a switch statement to take over that.428	 */429	switch (chan_type) {430	case IIO_ACCEL:431		base = FXOS8700_OUT_X_MSB;432		break;433	case IIO_MAGN:434		base = FXOS8700_M_OUT_X_MSB;435		break;436	default:437		return -EINVAL;438	}439 440	/* Block read 6 bytes of device output registers to avoid data loss */441	ret = regmap_bulk_read(data->regmap, base, data->buf,442			       sizeof(data->buf));443	if (ret)444		return ret;445 446	/* Convert axis to buffer index */447	reg = axis - IIO_MOD_X;448 449	/*450	 * Convert to native endianness. The accel data and magn data451	 * are signed, so a forced type conversion is needed.452	 */453	tmp = be16_to_cpu(data->buf[reg]);454 455	/*456	 * ACCEL output data registers contain the X-axis, Y-axis, and Z-axis457	 * 14-bit left-justified sample data and MAGN output data registers458	 * contain the X-axis, Y-axis, and Z-axis 16-bit sample data. Apply459	 * a signed 2 bits right shift to the readback raw data from ACCEL460	 * output data register and keep that from MAGN sensor as the origin.461	 * Value should be extended to 32 bit.462	 */463	switch (chan_type) {464	case IIO_ACCEL:465		tmp = tmp >> 2;466		break;467	case IIO_MAGN:468		/* Nothing to do */469		break;470	default:471		return -EINVAL;472	}473 474	/* Convert to native endianness */475	*val = sign_extend32(tmp, 15);476 477	return 0;478}479 480static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t,481			    int odr, int uodr)482{483	int i, ret, val;484	bool active_mode;485	static const int odr_num = ARRAY_SIZE(fxos8700_odr);486 487	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);488	if (ret)489		return ret;490 491	active_mode = val & FXOS8700_ACTIVE;492 493	if (active_mode) {494		/*495		 * The device must be in standby mode to change any of the496		 * other fields within CTRL_REG1497		 */498		ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,499				   val & ~FXOS8700_ACTIVE);500		if (ret)501			return ret;502	}503 504	for (i = 0; i < odr_num; i++)505		if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr)506			break;507 508	if (i >= odr_num)509		return -EINVAL;510 511	val &= ~FXOS8700_CTRL_ODR_MSK;512	val |= FIELD_PREP(FXOS8700_CTRL_ODR_MSK, fxos8700_odr[i].bits) | FXOS8700_ACTIVE;513	return regmap_write(data->regmap, FXOS8700_CTRL_REG1, val);514}515 516static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,517			    int *odr, int *uodr)518{519	int i, val, ret;520	static const int odr_num = ARRAY_SIZE(fxos8700_odr);521 522	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);523	if (ret)524		return ret;525 526	val = FIELD_GET(FXOS8700_CTRL_ODR_MSK, val);527 528	for (i = 0; i < odr_num; i++)529		if (val == fxos8700_odr[i].bits)530			break;531 532	if (i >= odr_num)533		return -EINVAL;534 535	*odr = fxos8700_odr[i].odr;536	*uodr = fxos8700_odr[i].uodr;537 538	return 0;539}540 541static int fxos8700_read_raw(struct iio_dev *indio_dev,542			     struct iio_chan_spec const *chan,543			     int *val, int *val2, long mask)544{545	int ret;546	struct fxos8700_data *data = iio_priv(indio_dev);547 548	switch (mask) {549	case IIO_CHAN_INFO_RAW:550		ret = fxos8700_get_data(data, chan->type, chan->channel2, val);551		if (ret)552			return ret;553		return IIO_VAL_INT;554	case IIO_CHAN_INFO_SCALE:555		*val = 0;556		ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type),557					 val2);558		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;559	case IIO_CHAN_INFO_SAMP_FREQ:560		ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type),561				       val, val2);562		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;563	default:564		return -EINVAL;565	}566}567 568static int fxos8700_write_raw(struct iio_dev *indio_dev,569			      struct iio_chan_spec const *chan,570			      int val, int val2, long mask)571{572	struct fxos8700_data *data = iio_priv(indio_dev);573 574	switch (mask) {575	case IIO_CHAN_INFO_SCALE:576		return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type),577					  val2);578	case IIO_CHAN_INFO_SAMP_FREQ:579		return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type),580					val, val2);581	default:582		return -EINVAL;583	}584}585 586static IIO_CONST_ATTR(in_accel_sampling_frequency_available,587		      "1.5625 6.25 12.5 50 100 200 400 800");588static IIO_CONST_ATTR(in_magn_sampling_frequency_available,589		      "1.5625 6.25 12.5 50 100 200 400 800");590static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976");591static IIO_CONST_ATTR(in_magn_scale_available, "0.001000");592 593static struct attribute *fxos8700_attrs[] = {594	&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,595	&iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr,596	&iio_const_attr_in_accel_scale_available.dev_attr.attr,597	&iio_const_attr_in_magn_scale_available.dev_attr.attr,598	NULL,599};600 601static const struct attribute_group fxos8700_attrs_group = {602	.attrs = fxos8700_attrs,603};604 605static const struct iio_info fxos8700_info = {606	.read_raw = fxos8700_read_raw,607	.write_raw = fxos8700_write_raw,608	.attrs = &fxos8700_attrs_group,609};610 611static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi)612{613	int ret;614	unsigned int val;615	struct device *dev = regmap_get_device(data->regmap);616 617	ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val);618	if (ret) {619		dev_err(dev, "Error reading chip id\n");620		return ret;621	}622	if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) {623		dev_err(dev, "Wrong chip id, got %x expected %x or %x\n",624			val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID);625		return -ENODEV;626	}627 628	ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true);629	if (ret)630		return ret;631 632	ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true);633	if (ret)634		return ret;635 636	/*637	 * The device must be in standby mode to change any of the other fields638	 * within CTRL_REG1639	 */640	ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00);641	if (ret)642		return ret;643 644	/* Set max oversample ratio (OSR) and both devices active */645	ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1,646			   FXOS8700_HMS_MASK | FXOS8700_OS_MASK);647	if (ret)648		return ret;649 650	/* Disable and rst min/max measurements & threshold */651	ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2,652			   FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS |653			   FXOS8700_MAXMIN_DIS);654	if (ret)655		return ret;656 657	/*658	 * Set max full-scale range (+/-8G) for ACCEL sensor in chip659	 * initialization then activate the device.660	 */661	ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);662	if (ret)663		return ret;664 665	/* Max ODR (800Hz individual or 400Hz hybrid), active mode */666	return regmap_update_bits(data->regmap, FXOS8700_CTRL_REG1,667				FXOS8700_CTRL_ODR_MSK | FXOS8700_ACTIVE,668				FIELD_PREP(FXOS8700_CTRL_ODR_MSK, FXOS8700_CTRL_ODR_MAX) |669				FXOS8700_ACTIVE);670}671 672static void fxos8700_chip_uninit(void *data)673{674	struct fxos8700_data *fxos8700_data = data;675 676	fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false);677	fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false);678}679 680int fxos8700_core_probe(struct device *dev, struct regmap *regmap,681			const char *name, bool use_spi)682{683	struct iio_dev *indio_dev;684	struct fxos8700_data *data;685	int ret;686 687	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));688	if (!indio_dev)689		return -ENOMEM;690 691	data = iio_priv(indio_dev);692	dev_set_drvdata(dev, indio_dev);693	data->regmap = regmap;694 695	ret = fxos8700_chip_init(data, use_spi);696	if (ret)697		return ret;698 699	ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data);700	if (ret)701		return ret;702 703	indio_dev->channels = fxos8700_channels;704	indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels);705	indio_dev->name = name ? name : "fxos8700";706	indio_dev->modes = INDIO_DIRECT_MODE;707	indio_dev->info = &fxos8700_info;708 709	return devm_iio_device_register(dev, indio_dev);710}711EXPORT_SYMBOL_GPL(fxos8700_core_probe);712 713MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");714MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver");715MODULE_LICENSE("GPL v2");716