131c24c1eSJean-Baptiste Maneyrol // SPDX-License-Identifier: GPL-2.0-or-later
231c24c1eSJean-Baptiste Maneyrol /*
331c24c1eSJean-Baptiste Maneyrol  * Copyright (C) 2020 Invensense, Inc.
431c24c1eSJean-Baptiste Maneyrol  */
531c24c1eSJean-Baptiste Maneyrol 
631c24c1eSJean-Baptiste Maneyrol #include <linux/kernel.h>
731c24c1eSJean-Baptiste Maneyrol #include <linux/device.h>
831c24c1eSJean-Baptiste Maneyrol #include <linux/module.h>
931c24c1eSJean-Baptiste Maneyrol #include <linux/slab.h>
1031c24c1eSJean-Baptiste Maneyrol #include <linux/delay.h>
1131c24c1eSJean-Baptiste Maneyrol #include <linux/mutex.h>
12e5efa104SJean-Baptiste Maneyrol #include <linux/interrupt.h>
13e5efa104SJean-Baptiste Maneyrol #include <linux/irq.h>
1431c24c1eSJean-Baptiste Maneyrol #include <linux/regulator/consumer.h>
1531c24c1eSJean-Baptiste Maneyrol #include <linux/pm_runtime.h>
16e5efa104SJean-Baptiste Maneyrol #include <linux/property.h>
1731c24c1eSJean-Baptiste Maneyrol #include <linux/regmap.h>
1831c24c1eSJean-Baptiste Maneyrol #include <linux/iio/iio.h>
1931c24c1eSJean-Baptiste Maneyrol 
2031c24c1eSJean-Baptiste Maneyrol #include "inv_icm42600.h"
217f85e42aSJean-Baptiste Maneyrol #include "inv_icm42600_buffer.h"
22ec74ae9fSJean-Baptiste Maneyrol #include "inv_icm42600_timestamp.h"
2331c24c1eSJean-Baptiste Maneyrol 
2431c24c1eSJean-Baptiste Maneyrol static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = {
2531c24c1eSJean-Baptiste Maneyrol 	{
2631c24c1eSJean-Baptiste Maneyrol 		.name = "user banks",
2731c24c1eSJean-Baptiste Maneyrol 		.range_min = 0x0000,
2831c24c1eSJean-Baptiste Maneyrol 		.range_max = 0x4FFF,
2931c24c1eSJean-Baptiste Maneyrol 		.selector_reg = INV_ICM42600_REG_BANK_SEL,
3031c24c1eSJean-Baptiste Maneyrol 		.selector_mask = INV_ICM42600_BANK_SEL_MASK,
3131c24c1eSJean-Baptiste Maneyrol 		.selector_shift = 0,
3231c24c1eSJean-Baptiste Maneyrol 		.window_start = 0,
3331c24c1eSJean-Baptiste Maneyrol 		.window_len = 0x1000,
3431c24c1eSJean-Baptiste Maneyrol 	},
3531c24c1eSJean-Baptiste Maneyrol };
3631c24c1eSJean-Baptiste Maneyrol 
3731c24c1eSJean-Baptiste Maneyrol const struct regmap_config inv_icm42600_regmap_config = {
3831c24c1eSJean-Baptiste Maneyrol 	.reg_bits = 8,
3931c24c1eSJean-Baptiste Maneyrol 	.val_bits = 8,
4031c24c1eSJean-Baptiste Maneyrol 	.max_register = 0x4FFF,
4131c24c1eSJean-Baptiste Maneyrol 	.ranges = inv_icm42600_regmap_ranges,
4231c24c1eSJean-Baptiste Maneyrol 	.num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges),
4331c24c1eSJean-Baptiste Maneyrol };
4431c24c1eSJean-Baptiste Maneyrol EXPORT_SYMBOL_GPL(inv_icm42600_regmap_config);
4531c24c1eSJean-Baptiste Maneyrol 
4631c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_hw {
4731c24c1eSJean-Baptiste Maneyrol 	uint8_t whoami;
4831c24c1eSJean-Baptiste Maneyrol 	const char *name;
4931c24c1eSJean-Baptiste Maneyrol 	const struct inv_icm42600_conf *conf;
5031c24c1eSJean-Baptiste Maneyrol };
5131c24c1eSJean-Baptiste Maneyrol 
5231c24c1eSJean-Baptiste Maneyrol /* chip initial default configuration */
5331c24c1eSJean-Baptiste Maneyrol static const struct inv_icm42600_conf inv_icm42600_default_conf = {
5431c24c1eSJean-Baptiste Maneyrol 	.gyro = {
5531c24c1eSJean-Baptiste Maneyrol 		.mode = INV_ICM42600_SENSOR_MODE_OFF,
5631c24c1eSJean-Baptiste Maneyrol 		.fs = INV_ICM42600_GYRO_FS_2000DPS,
5731c24c1eSJean-Baptiste Maneyrol 		.odr = INV_ICM42600_ODR_50HZ,
5831c24c1eSJean-Baptiste Maneyrol 		.filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
5931c24c1eSJean-Baptiste Maneyrol 	},
6031c24c1eSJean-Baptiste Maneyrol 	.accel = {
6131c24c1eSJean-Baptiste Maneyrol 		.mode = INV_ICM42600_SENSOR_MODE_OFF,
6231c24c1eSJean-Baptiste Maneyrol 		.fs = INV_ICM42600_ACCEL_FS_16G,
6331c24c1eSJean-Baptiste Maneyrol 		.odr = INV_ICM42600_ODR_50HZ,
6431c24c1eSJean-Baptiste Maneyrol 		.filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
6531c24c1eSJean-Baptiste Maneyrol 	},
6631c24c1eSJean-Baptiste Maneyrol 	.temp_en = false,
6731c24c1eSJean-Baptiste Maneyrol };
6831c24c1eSJean-Baptiste Maneyrol 
6931c24c1eSJean-Baptiste Maneyrol static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
7031c24c1eSJean-Baptiste Maneyrol 	[INV_CHIP_ICM42600] = {
7131c24c1eSJean-Baptiste Maneyrol 		.whoami = INV_ICM42600_WHOAMI_ICM42600,
7231c24c1eSJean-Baptiste Maneyrol 		.name = "icm42600",
7331c24c1eSJean-Baptiste Maneyrol 		.conf = &inv_icm42600_default_conf,
7431c24c1eSJean-Baptiste Maneyrol 	},
7531c24c1eSJean-Baptiste Maneyrol 	[INV_CHIP_ICM42602] = {
7631c24c1eSJean-Baptiste Maneyrol 		.whoami = INV_ICM42600_WHOAMI_ICM42602,
7731c24c1eSJean-Baptiste Maneyrol 		.name = "icm42602",
7831c24c1eSJean-Baptiste Maneyrol 		.conf = &inv_icm42600_default_conf,
7931c24c1eSJean-Baptiste Maneyrol 	},
8031c24c1eSJean-Baptiste Maneyrol 	[INV_CHIP_ICM42605] = {
8131c24c1eSJean-Baptiste Maneyrol 		.whoami = INV_ICM42600_WHOAMI_ICM42605,
8231c24c1eSJean-Baptiste Maneyrol 		.name = "icm42605",
8331c24c1eSJean-Baptiste Maneyrol 		.conf = &inv_icm42600_default_conf,
8431c24c1eSJean-Baptiste Maneyrol 	},
8531c24c1eSJean-Baptiste Maneyrol 	[INV_CHIP_ICM42622] = {
8631c24c1eSJean-Baptiste Maneyrol 		.whoami = INV_ICM42600_WHOAMI_ICM42622,
8731c24c1eSJean-Baptiste Maneyrol 		.name = "icm42622",
8831c24c1eSJean-Baptiste Maneyrol 		.conf = &inv_icm42600_default_conf,
8931c24c1eSJean-Baptiste Maneyrol 	},
9031c24c1eSJean-Baptiste Maneyrol };
9131c24c1eSJean-Baptiste Maneyrol 
9231c24c1eSJean-Baptiste Maneyrol const struct iio_mount_matrix *
9331c24c1eSJean-Baptiste Maneyrol inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev,
9431c24c1eSJean-Baptiste Maneyrol 			      const struct iio_chan_spec *chan)
9531c24c1eSJean-Baptiste Maneyrol {
9631c24c1eSJean-Baptiste Maneyrol 	const struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
9731c24c1eSJean-Baptiste Maneyrol 
9831c24c1eSJean-Baptiste Maneyrol 	return &st->orientation;
9931c24c1eSJean-Baptiste Maneyrol }
10031c24c1eSJean-Baptiste Maneyrol 
10131c24c1eSJean-Baptiste Maneyrol uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr)
10231c24c1eSJean-Baptiste Maneyrol {
10331c24c1eSJean-Baptiste Maneyrol 	static uint32_t odr_periods[INV_ICM42600_ODR_NB] = {
10431c24c1eSJean-Baptiste Maneyrol 		/* reserved values */
10531c24c1eSJean-Baptiste Maneyrol 		0, 0, 0,
10631c24c1eSJean-Baptiste Maneyrol 		/* 8kHz */
10731c24c1eSJean-Baptiste Maneyrol 		125000,
10831c24c1eSJean-Baptiste Maneyrol 		/* 4kHz */
10931c24c1eSJean-Baptiste Maneyrol 		250000,
11031c24c1eSJean-Baptiste Maneyrol 		/* 2kHz */
11131c24c1eSJean-Baptiste Maneyrol 		500000,
11231c24c1eSJean-Baptiste Maneyrol 		/* 1kHz */
11331c24c1eSJean-Baptiste Maneyrol 		1000000,
11431c24c1eSJean-Baptiste Maneyrol 		/* 200Hz */
11531c24c1eSJean-Baptiste Maneyrol 		5000000,
11631c24c1eSJean-Baptiste Maneyrol 		/* 100Hz */
11731c24c1eSJean-Baptiste Maneyrol 		10000000,
11831c24c1eSJean-Baptiste Maneyrol 		/* 50Hz */
11931c24c1eSJean-Baptiste Maneyrol 		20000000,
12031c24c1eSJean-Baptiste Maneyrol 		/* 25Hz */
12131c24c1eSJean-Baptiste Maneyrol 		40000000,
12231c24c1eSJean-Baptiste Maneyrol 		/* 12.5Hz */
12331c24c1eSJean-Baptiste Maneyrol 		80000000,
12431c24c1eSJean-Baptiste Maneyrol 		/* 6.25Hz */
12531c24c1eSJean-Baptiste Maneyrol 		160000000,
12631c24c1eSJean-Baptiste Maneyrol 		/* 3.125Hz */
12731c24c1eSJean-Baptiste Maneyrol 		320000000,
12831c24c1eSJean-Baptiste Maneyrol 		/* 1.5625Hz */
12931c24c1eSJean-Baptiste Maneyrol 		640000000,
13031c24c1eSJean-Baptiste Maneyrol 		/* 500Hz */
13131c24c1eSJean-Baptiste Maneyrol 		2000000,
13231c24c1eSJean-Baptiste Maneyrol 	};
13331c24c1eSJean-Baptiste Maneyrol 
13431c24c1eSJean-Baptiste Maneyrol 	return odr_periods[odr];
13531c24c1eSJean-Baptiste Maneyrol }
13631c24c1eSJean-Baptiste Maneyrol 
13731c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_set_pwr_mgmt0(struct inv_icm42600_state *st,
13831c24c1eSJean-Baptiste Maneyrol 				      enum inv_icm42600_sensor_mode gyro,
13931c24c1eSJean-Baptiste Maneyrol 				      enum inv_icm42600_sensor_mode accel,
14031c24c1eSJean-Baptiste Maneyrol 				      bool temp, unsigned int *sleep_ms)
14131c24c1eSJean-Baptiste Maneyrol {
14231c24c1eSJean-Baptiste Maneyrol 	enum inv_icm42600_sensor_mode oldgyro = st->conf.gyro.mode;
14331c24c1eSJean-Baptiste Maneyrol 	enum inv_icm42600_sensor_mode oldaccel = st->conf.accel.mode;
14431c24c1eSJean-Baptiste Maneyrol 	bool oldtemp = st->conf.temp_en;
14531c24c1eSJean-Baptiste Maneyrol 	unsigned int sleepval;
14631c24c1eSJean-Baptiste Maneyrol 	unsigned int val;
14731c24c1eSJean-Baptiste Maneyrol 	int ret;
14831c24c1eSJean-Baptiste Maneyrol 
14931c24c1eSJean-Baptiste Maneyrol 	/* if nothing changed, exit */
15031c24c1eSJean-Baptiste Maneyrol 	if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
15131c24c1eSJean-Baptiste Maneyrol 		return 0;
15231c24c1eSJean-Baptiste Maneyrol 
15331c24c1eSJean-Baptiste Maneyrol 	val = INV_ICM42600_PWR_MGMT0_GYRO(gyro) |
15431c24c1eSJean-Baptiste Maneyrol 	      INV_ICM42600_PWR_MGMT0_ACCEL(accel);
15531c24c1eSJean-Baptiste Maneyrol 	if (!temp)
15631c24c1eSJean-Baptiste Maneyrol 		val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS;
15731c24c1eSJean-Baptiste Maneyrol 	ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val);
15831c24c1eSJean-Baptiste Maneyrol 	if (ret)
15931c24c1eSJean-Baptiste Maneyrol 		return ret;
16031c24c1eSJean-Baptiste Maneyrol 
16131c24c1eSJean-Baptiste Maneyrol 	st->conf.gyro.mode = gyro;
16231c24c1eSJean-Baptiste Maneyrol 	st->conf.accel.mode = accel;
16331c24c1eSJean-Baptiste Maneyrol 	st->conf.temp_en = temp;
16431c24c1eSJean-Baptiste Maneyrol 
16531c24c1eSJean-Baptiste Maneyrol 	/* compute required wait time for sensors to stabilize */
16631c24c1eSJean-Baptiste Maneyrol 	sleepval = 0;
16731c24c1eSJean-Baptiste Maneyrol 	/* temperature stabilization time */
16831c24c1eSJean-Baptiste Maneyrol 	if (temp && !oldtemp) {
16931c24c1eSJean-Baptiste Maneyrol 		if (sleepval < INV_ICM42600_TEMP_STARTUP_TIME_MS)
17031c24c1eSJean-Baptiste Maneyrol 			sleepval = INV_ICM42600_TEMP_STARTUP_TIME_MS;
17131c24c1eSJean-Baptiste Maneyrol 	}
17231c24c1eSJean-Baptiste Maneyrol 	/* accel startup time */
17331c24c1eSJean-Baptiste Maneyrol 	if (accel != oldaccel && oldaccel == INV_ICM42600_SENSOR_MODE_OFF) {
17431c24c1eSJean-Baptiste Maneyrol 		/* block any register write for at least 200 µs */
17531c24c1eSJean-Baptiste Maneyrol 		usleep_range(200, 300);
17631c24c1eSJean-Baptiste Maneyrol 		if (sleepval < INV_ICM42600_ACCEL_STARTUP_TIME_MS)
17731c24c1eSJean-Baptiste Maneyrol 			sleepval = INV_ICM42600_ACCEL_STARTUP_TIME_MS;
17831c24c1eSJean-Baptiste Maneyrol 	}
17931c24c1eSJean-Baptiste Maneyrol 	if (gyro != oldgyro) {
18031c24c1eSJean-Baptiste Maneyrol 		/* gyro startup time */
18131c24c1eSJean-Baptiste Maneyrol 		if (oldgyro == INV_ICM42600_SENSOR_MODE_OFF) {
18231c24c1eSJean-Baptiste Maneyrol 			/* block any register write for at least 200 µs */
18331c24c1eSJean-Baptiste Maneyrol 			usleep_range(200, 300);
18431c24c1eSJean-Baptiste Maneyrol 			if (sleepval < INV_ICM42600_GYRO_STARTUP_TIME_MS)
18531c24c1eSJean-Baptiste Maneyrol 				sleepval = INV_ICM42600_GYRO_STARTUP_TIME_MS;
18631c24c1eSJean-Baptiste Maneyrol 		/* gyro stop time */
18731c24c1eSJean-Baptiste Maneyrol 		} else if (gyro == INV_ICM42600_SENSOR_MODE_OFF) {
18831c24c1eSJean-Baptiste Maneyrol 			if (sleepval < INV_ICM42600_GYRO_STOP_TIME_MS)
18931c24c1eSJean-Baptiste Maneyrol 				sleepval =  INV_ICM42600_GYRO_STOP_TIME_MS;
19031c24c1eSJean-Baptiste Maneyrol 		}
19131c24c1eSJean-Baptiste Maneyrol 	}
19231c24c1eSJean-Baptiste Maneyrol 
19331c24c1eSJean-Baptiste Maneyrol 	/* deferred sleep value if sleep pointer is provided or direct sleep */
19431c24c1eSJean-Baptiste Maneyrol 	if (sleep_ms)
19531c24c1eSJean-Baptiste Maneyrol 		*sleep_ms = sleepval;
19631c24c1eSJean-Baptiste Maneyrol 	else if (sleepval)
19731c24c1eSJean-Baptiste Maneyrol 		msleep(sleepval);
19831c24c1eSJean-Baptiste Maneyrol 
19931c24c1eSJean-Baptiste Maneyrol 	return 0;
20031c24c1eSJean-Baptiste Maneyrol }
20131c24c1eSJean-Baptiste Maneyrol 
20231c24c1eSJean-Baptiste Maneyrol int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
20331c24c1eSJean-Baptiste Maneyrol 				struct inv_icm42600_sensor_conf *conf,
20431c24c1eSJean-Baptiste Maneyrol 				unsigned int *sleep_ms)
20531c24c1eSJean-Baptiste Maneyrol {
20631c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_sensor_conf *oldconf = &st->conf.accel;
20731c24c1eSJean-Baptiste Maneyrol 	unsigned int val;
20831c24c1eSJean-Baptiste Maneyrol 	int ret;
20931c24c1eSJean-Baptiste Maneyrol 
21031c24c1eSJean-Baptiste Maneyrol 	/* Sanitize missing values with current values */
21131c24c1eSJean-Baptiste Maneyrol 	if (conf->mode < 0)
21231c24c1eSJean-Baptiste Maneyrol 		conf->mode = oldconf->mode;
21331c24c1eSJean-Baptiste Maneyrol 	if (conf->fs < 0)
21431c24c1eSJean-Baptiste Maneyrol 		conf->fs = oldconf->fs;
21531c24c1eSJean-Baptiste Maneyrol 	if (conf->odr < 0)
21631c24c1eSJean-Baptiste Maneyrol 		conf->odr = oldconf->odr;
21731c24c1eSJean-Baptiste Maneyrol 	if (conf->filter < 0)
21831c24c1eSJean-Baptiste Maneyrol 		conf->filter = oldconf->filter;
21931c24c1eSJean-Baptiste Maneyrol 
22031c24c1eSJean-Baptiste Maneyrol 	/* set ACCEL_CONFIG0 register (accel fullscale & odr) */
22131c24c1eSJean-Baptiste Maneyrol 	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
22231c24c1eSJean-Baptiste Maneyrol 		val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) |
22331c24c1eSJean-Baptiste Maneyrol 		      INV_ICM42600_ACCEL_CONFIG0_ODR(conf->odr);
22431c24c1eSJean-Baptiste Maneyrol 		ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val);
22531c24c1eSJean-Baptiste Maneyrol 		if (ret)
22631c24c1eSJean-Baptiste Maneyrol 			return ret;
22731c24c1eSJean-Baptiste Maneyrol 		oldconf->fs = conf->fs;
22831c24c1eSJean-Baptiste Maneyrol 		oldconf->odr = conf->odr;
22931c24c1eSJean-Baptiste Maneyrol 	}
23031c24c1eSJean-Baptiste Maneyrol 
23131c24c1eSJean-Baptiste Maneyrol 	/* set GYRO_ACCEL_CONFIG0 register (accel filter) */
23231c24c1eSJean-Baptiste Maneyrol 	if (conf->filter != oldconf->filter) {
23331c24c1eSJean-Baptiste Maneyrol 		val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->filter) |
23431c24c1eSJean-Baptiste Maneyrol 		      INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(st->conf.gyro.filter);
23531c24c1eSJean-Baptiste Maneyrol 		ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
23631c24c1eSJean-Baptiste Maneyrol 		if (ret)
23731c24c1eSJean-Baptiste Maneyrol 			return ret;
23831c24c1eSJean-Baptiste Maneyrol 		oldconf->filter = conf->filter;
23931c24c1eSJean-Baptiste Maneyrol 	}
24031c24c1eSJean-Baptiste Maneyrol 
24131c24c1eSJean-Baptiste Maneyrol 	/* set PWR_MGMT0 register (accel sensor mode) */
24231c24c1eSJean-Baptiste Maneyrol 	return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
24331c24c1eSJean-Baptiste Maneyrol 					  st->conf.temp_en, sleep_ms);
24431c24c1eSJean-Baptiste Maneyrol }
24531c24c1eSJean-Baptiste Maneyrol 
24631c24c1eSJean-Baptiste Maneyrol int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st,
24731c24c1eSJean-Baptiste Maneyrol 			       struct inv_icm42600_sensor_conf *conf,
24831c24c1eSJean-Baptiste Maneyrol 			       unsigned int *sleep_ms)
24931c24c1eSJean-Baptiste Maneyrol {
25031c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_sensor_conf *oldconf = &st->conf.gyro;
25131c24c1eSJean-Baptiste Maneyrol 	unsigned int val;
25231c24c1eSJean-Baptiste Maneyrol 	int ret;
25331c24c1eSJean-Baptiste Maneyrol 
25431c24c1eSJean-Baptiste Maneyrol 	/* sanitize missing values with current values */
25531c24c1eSJean-Baptiste Maneyrol 	if (conf->mode < 0)
25631c24c1eSJean-Baptiste Maneyrol 		conf->mode = oldconf->mode;
25731c24c1eSJean-Baptiste Maneyrol 	if (conf->fs < 0)
25831c24c1eSJean-Baptiste Maneyrol 		conf->fs = oldconf->fs;
25931c24c1eSJean-Baptiste Maneyrol 	if (conf->odr < 0)
26031c24c1eSJean-Baptiste Maneyrol 		conf->odr = oldconf->odr;
26131c24c1eSJean-Baptiste Maneyrol 	if (conf->filter < 0)
26231c24c1eSJean-Baptiste Maneyrol 		conf->filter = oldconf->filter;
26331c24c1eSJean-Baptiste Maneyrol 
26431c24c1eSJean-Baptiste Maneyrol 	/* set GYRO_CONFIG0 register (gyro fullscale & odr) */
26531c24c1eSJean-Baptiste Maneyrol 	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
26631c24c1eSJean-Baptiste Maneyrol 		val = INV_ICM42600_GYRO_CONFIG0_FS(conf->fs) |
26731c24c1eSJean-Baptiste Maneyrol 		      INV_ICM42600_GYRO_CONFIG0_ODR(conf->odr);
26831c24c1eSJean-Baptiste Maneyrol 		ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val);
26931c24c1eSJean-Baptiste Maneyrol 		if (ret)
27031c24c1eSJean-Baptiste Maneyrol 			return ret;
27131c24c1eSJean-Baptiste Maneyrol 		oldconf->fs = conf->fs;
27231c24c1eSJean-Baptiste Maneyrol 		oldconf->odr = conf->odr;
27331c24c1eSJean-Baptiste Maneyrol 	}
27431c24c1eSJean-Baptiste Maneyrol 
27531c24c1eSJean-Baptiste Maneyrol 	/* set GYRO_ACCEL_CONFIG0 register (gyro filter) */
27631c24c1eSJean-Baptiste Maneyrol 	if (conf->filter != oldconf->filter) {
27731c24c1eSJean-Baptiste Maneyrol 		val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(st->conf.accel.filter) |
27831c24c1eSJean-Baptiste Maneyrol 		      INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->filter);
27931c24c1eSJean-Baptiste Maneyrol 		ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
28031c24c1eSJean-Baptiste Maneyrol 		if (ret)
28131c24c1eSJean-Baptiste Maneyrol 			return ret;
28231c24c1eSJean-Baptiste Maneyrol 		oldconf->filter = conf->filter;
28331c24c1eSJean-Baptiste Maneyrol 	}
28431c24c1eSJean-Baptiste Maneyrol 
28531c24c1eSJean-Baptiste Maneyrol 	/* set PWR_MGMT0 register (gyro sensor mode) */
28631c24c1eSJean-Baptiste Maneyrol 	return inv_icm42600_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
28731c24c1eSJean-Baptiste Maneyrol 					  st->conf.temp_en, sleep_ms);
28831c24c1eSJean-Baptiste Maneyrol 
28931c24c1eSJean-Baptiste Maneyrol 	return 0;
29031c24c1eSJean-Baptiste Maneyrol }
29131c24c1eSJean-Baptiste Maneyrol 
29231c24c1eSJean-Baptiste Maneyrol int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
29331c24c1eSJean-Baptiste Maneyrol 			       unsigned int *sleep_ms)
29431c24c1eSJean-Baptiste Maneyrol {
29531c24c1eSJean-Baptiste Maneyrol 	return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode,
29631c24c1eSJean-Baptiste Maneyrol 					  st->conf.accel.mode, enable,
29731c24c1eSJean-Baptiste Maneyrol 					  sleep_ms);
29831c24c1eSJean-Baptiste Maneyrol }
29931c24c1eSJean-Baptiste Maneyrol 
30031c24c1eSJean-Baptiste Maneyrol int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
30131c24c1eSJean-Baptiste Maneyrol 			     unsigned int writeval, unsigned int *readval)
30231c24c1eSJean-Baptiste Maneyrol {
30331c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
30431c24c1eSJean-Baptiste Maneyrol 	int ret;
30531c24c1eSJean-Baptiste Maneyrol 
30631c24c1eSJean-Baptiste Maneyrol 	mutex_lock(&st->lock);
30731c24c1eSJean-Baptiste Maneyrol 
30831c24c1eSJean-Baptiste Maneyrol 	if (readval)
30931c24c1eSJean-Baptiste Maneyrol 		ret = regmap_read(st->map, reg, readval);
31031c24c1eSJean-Baptiste Maneyrol 	else
31131c24c1eSJean-Baptiste Maneyrol 		ret = regmap_write(st->map, reg, writeval);
31231c24c1eSJean-Baptiste Maneyrol 
31331c24c1eSJean-Baptiste Maneyrol 	mutex_unlock(&st->lock);
31431c24c1eSJean-Baptiste Maneyrol 
31531c24c1eSJean-Baptiste Maneyrol 	return ret;
31631c24c1eSJean-Baptiste Maneyrol }
31731c24c1eSJean-Baptiste Maneyrol 
31831c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_set_conf(struct inv_icm42600_state *st,
31931c24c1eSJean-Baptiste Maneyrol 				 const struct inv_icm42600_conf *conf)
32031c24c1eSJean-Baptiste Maneyrol {
32131c24c1eSJean-Baptiste Maneyrol 	unsigned int val;
32231c24c1eSJean-Baptiste Maneyrol 	int ret;
32331c24c1eSJean-Baptiste Maneyrol 
32431c24c1eSJean-Baptiste Maneyrol 	/* set PWR_MGMT0 register (gyro & accel sensor mode, temp enabled) */
32531c24c1eSJean-Baptiste Maneyrol 	val = INV_ICM42600_PWR_MGMT0_GYRO(conf->gyro.mode) |
32631c24c1eSJean-Baptiste Maneyrol 	      INV_ICM42600_PWR_MGMT0_ACCEL(conf->accel.mode);
32731c24c1eSJean-Baptiste Maneyrol 	if (!conf->temp_en)
32831c24c1eSJean-Baptiste Maneyrol 		val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS;
32931c24c1eSJean-Baptiste Maneyrol 	ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val);
33031c24c1eSJean-Baptiste Maneyrol 	if (ret)
33131c24c1eSJean-Baptiste Maneyrol 		return ret;
33231c24c1eSJean-Baptiste Maneyrol 
33331c24c1eSJean-Baptiste Maneyrol 	/* set GYRO_CONFIG0 register (gyro fullscale & odr) */
33431c24c1eSJean-Baptiste Maneyrol 	val = INV_ICM42600_GYRO_CONFIG0_FS(conf->gyro.fs) |
33531c24c1eSJean-Baptiste Maneyrol 	      INV_ICM42600_GYRO_CONFIG0_ODR(conf->gyro.odr);
33631c24c1eSJean-Baptiste Maneyrol 	ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val);
33731c24c1eSJean-Baptiste Maneyrol 	if (ret)
33831c24c1eSJean-Baptiste Maneyrol 		return ret;
33931c24c1eSJean-Baptiste Maneyrol 
34031c24c1eSJean-Baptiste Maneyrol 	/* set ACCEL_CONFIG0 register (accel fullscale & odr) */
34131c24c1eSJean-Baptiste Maneyrol 	val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->accel.fs) |
34231c24c1eSJean-Baptiste Maneyrol 	      INV_ICM42600_ACCEL_CONFIG0_ODR(conf->accel.odr);
34331c24c1eSJean-Baptiste Maneyrol 	ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val);
34431c24c1eSJean-Baptiste Maneyrol 	if (ret)
34531c24c1eSJean-Baptiste Maneyrol 		return ret;
34631c24c1eSJean-Baptiste Maneyrol 
34731c24c1eSJean-Baptiste Maneyrol 	/* set GYRO_ACCEL_CONFIG0 register (gyro & accel filters) */
34831c24c1eSJean-Baptiste Maneyrol 	val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->accel.filter) |
34931c24c1eSJean-Baptiste Maneyrol 	      INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->gyro.filter);
35031c24c1eSJean-Baptiste Maneyrol 	ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
35131c24c1eSJean-Baptiste Maneyrol 	if (ret)
35231c24c1eSJean-Baptiste Maneyrol 		return ret;
35331c24c1eSJean-Baptiste Maneyrol 
35431c24c1eSJean-Baptiste Maneyrol 	/* update internal conf */
35531c24c1eSJean-Baptiste Maneyrol 	st->conf = *conf;
35631c24c1eSJean-Baptiste Maneyrol 
35731c24c1eSJean-Baptiste Maneyrol 	return 0;
35831c24c1eSJean-Baptiste Maneyrol }
35931c24c1eSJean-Baptiste Maneyrol 
36031c24c1eSJean-Baptiste Maneyrol /**
36131c24c1eSJean-Baptiste Maneyrol  *  inv_icm42600_setup() - check and setup chip
36231c24c1eSJean-Baptiste Maneyrol  *  @st:	driver internal state
36331c24c1eSJean-Baptiste Maneyrol  *  @bus_setup:	callback for setting up bus specific registers
36431c24c1eSJean-Baptiste Maneyrol  *
36531c24c1eSJean-Baptiste Maneyrol  *  Returns 0 on success, a negative error code otherwise.
36631c24c1eSJean-Baptiste Maneyrol  */
36731c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_setup(struct inv_icm42600_state *st,
36831c24c1eSJean-Baptiste Maneyrol 			      inv_icm42600_bus_setup bus_setup)
36931c24c1eSJean-Baptiste Maneyrol {
37031c24c1eSJean-Baptiste Maneyrol 	const struct inv_icm42600_hw *hw = &inv_icm42600_hw[st->chip];
37131c24c1eSJean-Baptiste Maneyrol 	const struct device *dev = regmap_get_device(st->map);
37231c24c1eSJean-Baptiste Maneyrol 	unsigned int val;
37331c24c1eSJean-Baptiste Maneyrol 	int ret;
37431c24c1eSJean-Baptiste Maneyrol 
37531c24c1eSJean-Baptiste Maneyrol 	/* check chip self-identification value */
37631c24c1eSJean-Baptiste Maneyrol 	ret = regmap_read(st->map, INV_ICM42600_REG_WHOAMI, &val);
37731c24c1eSJean-Baptiste Maneyrol 	if (ret)
37831c24c1eSJean-Baptiste Maneyrol 		return ret;
37931c24c1eSJean-Baptiste Maneyrol 	if (val != hw->whoami) {
38031c24c1eSJean-Baptiste Maneyrol 		dev_err(dev, "invalid whoami %#02x expected %#02x (%s)\n",
38131c24c1eSJean-Baptiste Maneyrol 			val, hw->whoami, hw->name);
38231c24c1eSJean-Baptiste Maneyrol 		return -ENODEV;
38331c24c1eSJean-Baptiste Maneyrol 	}
38431c24c1eSJean-Baptiste Maneyrol 	st->name = hw->name;
38531c24c1eSJean-Baptiste Maneyrol 
38631c24c1eSJean-Baptiste Maneyrol 	/* reset to make sure previous state are not there */
38731c24c1eSJean-Baptiste Maneyrol 	ret = regmap_write(st->map, INV_ICM42600_REG_DEVICE_CONFIG,
38831c24c1eSJean-Baptiste Maneyrol 			   INV_ICM42600_DEVICE_CONFIG_SOFT_RESET);
38931c24c1eSJean-Baptiste Maneyrol 	if (ret)
39031c24c1eSJean-Baptiste Maneyrol 		return ret;
39131c24c1eSJean-Baptiste Maneyrol 	msleep(INV_ICM42600_RESET_TIME_MS);
39231c24c1eSJean-Baptiste Maneyrol 
39331c24c1eSJean-Baptiste Maneyrol 	ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &val);
39431c24c1eSJean-Baptiste Maneyrol 	if (ret)
39531c24c1eSJean-Baptiste Maneyrol 		return ret;
39631c24c1eSJean-Baptiste Maneyrol 	if (!(val & INV_ICM42600_INT_STATUS_RESET_DONE)) {
39731c24c1eSJean-Baptiste Maneyrol 		dev_err(dev, "reset error, reset done bit not set\n");
39831c24c1eSJean-Baptiste Maneyrol 		return -ENODEV;
39931c24c1eSJean-Baptiste Maneyrol 	}
40031c24c1eSJean-Baptiste Maneyrol 
40131c24c1eSJean-Baptiste Maneyrol 	/* set chip bus configuration */
40231c24c1eSJean-Baptiste Maneyrol 	ret = bus_setup(st);
40331c24c1eSJean-Baptiste Maneyrol 	if (ret)
40431c24c1eSJean-Baptiste Maneyrol 		return ret;
40531c24c1eSJean-Baptiste Maneyrol 
40631c24c1eSJean-Baptiste Maneyrol 	/* sensor data in big-endian (default) */
40731c24c1eSJean-Baptiste Maneyrol 	ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
40831c24c1eSJean-Baptiste Maneyrol 				 INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN,
40931c24c1eSJean-Baptiste Maneyrol 				 INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
41031c24c1eSJean-Baptiste Maneyrol 	if (ret)
41131c24c1eSJean-Baptiste Maneyrol 		return ret;
41231c24c1eSJean-Baptiste Maneyrol 
41331c24c1eSJean-Baptiste Maneyrol 	return inv_icm42600_set_conf(st, hw->conf);
41431c24c1eSJean-Baptiste Maneyrol }
41531c24c1eSJean-Baptiste Maneyrol 
416ec74ae9fSJean-Baptiste Maneyrol static irqreturn_t inv_icm42600_irq_timestamp(int irq, void *_data)
417ec74ae9fSJean-Baptiste Maneyrol {
418ec74ae9fSJean-Baptiste Maneyrol 	struct inv_icm42600_state *st = _data;
419ec74ae9fSJean-Baptiste Maneyrol 
420ec74ae9fSJean-Baptiste Maneyrol 	st->timestamp.gyro = iio_get_time_ns(st->indio_gyro);
421ec74ae9fSJean-Baptiste Maneyrol 	st->timestamp.accel = iio_get_time_ns(st->indio_accel);
422ec74ae9fSJean-Baptiste Maneyrol 
423ec74ae9fSJean-Baptiste Maneyrol 	return IRQ_WAKE_THREAD;
424ec74ae9fSJean-Baptiste Maneyrol }
425ec74ae9fSJean-Baptiste Maneyrol 
426e5efa104SJean-Baptiste Maneyrol static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
427e5efa104SJean-Baptiste Maneyrol {
428e5efa104SJean-Baptiste Maneyrol 	struct inv_icm42600_state *st = _data;
429e5efa104SJean-Baptiste Maneyrol 	struct device *dev = regmap_get_device(st->map);
430e5efa104SJean-Baptiste Maneyrol 	unsigned int status;
431e5efa104SJean-Baptiste Maneyrol 	int ret;
432e5efa104SJean-Baptiste Maneyrol 
433e5efa104SJean-Baptiste Maneyrol 	mutex_lock(&st->lock);
434e5efa104SJean-Baptiste Maneyrol 
435e5efa104SJean-Baptiste Maneyrol 	ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &status);
436e5efa104SJean-Baptiste Maneyrol 	if (ret)
437e5efa104SJean-Baptiste Maneyrol 		goto out_unlock;
438e5efa104SJean-Baptiste Maneyrol 
439e5efa104SJean-Baptiste Maneyrol 	/* FIFO full */
440e5efa104SJean-Baptiste Maneyrol 	if (status & INV_ICM42600_INT_STATUS_FIFO_FULL)
441e5efa104SJean-Baptiste Maneyrol 		dev_warn(dev, "FIFO full data lost!\n");
442e5efa104SJean-Baptiste Maneyrol 
4437f85e42aSJean-Baptiste Maneyrol 	/* FIFO threshold reached */
4447f85e42aSJean-Baptiste Maneyrol 	if (status & INV_ICM42600_INT_STATUS_FIFO_THS) {
4457f85e42aSJean-Baptiste Maneyrol 		ret = inv_icm42600_buffer_fifo_read(st, 0);
4467f85e42aSJean-Baptiste Maneyrol 		if (ret) {
4477f85e42aSJean-Baptiste Maneyrol 			dev_err(dev, "FIFO read error %d\n", ret);
4487f85e42aSJean-Baptiste Maneyrol 			goto out_unlock;
4497f85e42aSJean-Baptiste Maneyrol 		}
4507f85e42aSJean-Baptiste Maneyrol 		ret = inv_icm42600_buffer_fifo_parse(st);
4517f85e42aSJean-Baptiste Maneyrol 		if (ret)
4527f85e42aSJean-Baptiste Maneyrol 			dev_err(dev, "FIFO parsing error %d\n", ret);
4537f85e42aSJean-Baptiste Maneyrol 	}
4547f85e42aSJean-Baptiste Maneyrol 
455e5efa104SJean-Baptiste Maneyrol out_unlock:
456e5efa104SJean-Baptiste Maneyrol 	mutex_unlock(&st->lock);
457e5efa104SJean-Baptiste Maneyrol 	return IRQ_HANDLED;
458e5efa104SJean-Baptiste Maneyrol }
459e5efa104SJean-Baptiste Maneyrol 
460e5efa104SJean-Baptiste Maneyrol /**
461e5efa104SJean-Baptiste Maneyrol  * inv_icm42600_irq_init() - initialize int pin and interrupt handler
462e5efa104SJean-Baptiste Maneyrol  * @st:		driver internal state
463e5efa104SJean-Baptiste Maneyrol  * @irq:	irq number
464e5efa104SJean-Baptiste Maneyrol  * @irq_type:	irq trigger type
465e5efa104SJean-Baptiste Maneyrol  * @open_drain:	true if irq is open drain, false for push-pull
466e5efa104SJean-Baptiste Maneyrol  *
467e5efa104SJean-Baptiste Maneyrol  * Returns 0 on success, a negative error code otherwise.
468e5efa104SJean-Baptiste Maneyrol  */
469e5efa104SJean-Baptiste Maneyrol static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq,
470e5efa104SJean-Baptiste Maneyrol 				 int irq_type, bool open_drain)
471e5efa104SJean-Baptiste Maneyrol {
472e5efa104SJean-Baptiste Maneyrol 	struct device *dev = regmap_get_device(st->map);
473e5efa104SJean-Baptiste Maneyrol 	unsigned int val;
474e5efa104SJean-Baptiste Maneyrol 	int ret;
475e5efa104SJean-Baptiste Maneyrol 
476e5efa104SJean-Baptiste Maneyrol 	/* configure INT1 interrupt: default is active low on edge */
477e5efa104SJean-Baptiste Maneyrol 	switch (irq_type) {
478e5efa104SJean-Baptiste Maneyrol 	case IRQF_TRIGGER_RISING:
479e5efa104SJean-Baptiste Maneyrol 	case IRQF_TRIGGER_HIGH:
480e5efa104SJean-Baptiste Maneyrol 		val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH;
481e5efa104SJean-Baptiste Maneyrol 		break;
482e5efa104SJean-Baptiste Maneyrol 	default:
483e5efa104SJean-Baptiste Maneyrol 		val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW;
484e5efa104SJean-Baptiste Maneyrol 		break;
485e5efa104SJean-Baptiste Maneyrol 	}
486e5efa104SJean-Baptiste Maneyrol 
487e5efa104SJean-Baptiste Maneyrol 	switch (irq_type) {
488e5efa104SJean-Baptiste Maneyrol 	case IRQF_TRIGGER_LOW:
489e5efa104SJean-Baptiste Maneyrol 	case IRQF_TRIGGER_HIGH:
490e5efa104SJean-Baptiste Maneyrol 		val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED;
491e5efa104SJean-Baptiste Maneyrol 		break;
492e5efa104SJean-Baptiste Maneyrol 	default:
493e5efa104SJean-Baptiste Maneyrol 		break;
494e5efa104SJean-Baptiste Maneyrol 	}
495e5efa104SJean-Baptiste Maneyrol 
496e5efa104SJean-Baptiste Maneyrol 	if (!open_drain)
497e5efa104SJean-Baptiste Maneyrol 		val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL;
498e5efa104SJean-Baptiste Maneyrol 
499e5efa104SJean-Baptiste Maneyrol 	ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val);
500e5efa104SJean-Baptiste Maneyrol 	if (ret)
501e5efa104SJean-Baptiste Maneyrol 		return ret;
502e5efa104SJean-Baptiste Maneyrol 
503e5efa104SJean-Baptiste Maneyrol 	/* Deassert async reset for proper INT pin operation (cf datasheet) */
504e5efa104SJean-Baptiste Maneyrol 	ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
505e5efa104SJean-Baptiste Maneyrol 				 INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0);
506e5efa104SJean-Baptiste Maneyrol 	if (ret)
507e5efa104SJean-Baptiste Maneyrol 		return ret;
508e5efa104SJean-Baptiste Maneyrol 
509ec74ae9fSJean-Baptiste Maneyrol 	return devm_request_threaded_irq(dev, irq, inv_icm42600_irq_timestamp,
510e5efa104SJean-Baptiste Maneyrol 					 inv_icm42600_irq_handler, irq_type,
511e5efa104SJean-Baptiste Maneyrol 					 "inv_icm42600", st);
512e5efa104SJean-Baptiste Maneyrol }
513e5efa104SJean-Baptiste Maneyrol 
51431c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st)
51531c24c1eSJean-Baptiste Maneyrol {
51631c24c1eSJean-Baptiste Maneyrol 	int ret;
51731c24c1eSJean-Baptiste Maneyrol 
51831c24c1eSJean-Baptiste Maneyrol 	ret = regulator_enable(st->vddio_supply);
51931c24c1eSJean-Baptiste Maneyrol 	if (ret)
52031c24c1eSJean-Baptiste Maneyrol 		return ret;
52131c24c1eSJean-Baptiste Maneyrol 
52231c24c1eSJean-Baptiste Maneyrol 	/* wait a little for supply ramp */
52331c24c1eSJean-Baptiste Maneyrol 	usleep_range(3000, 4000);
52431c24c1eSJean-Baptiste Maneyrol 
52531c24c1eSJean-Baptiste Maneyrol 	return 0;
52631c24c1eSJean-Baptiste Maneyrol }
52731c24c1eSJean-Baptiste Maneyrol 
52831c24c1eSJean-Baptiste Maneyrol static void inv_icm42600_disable_vdd_reg(void *_data)
52931c24c1eSJean-Baptiste Maneyrol {
53031c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_state *st = _data;
53131c24c1eSJean-Baptiste Maneyrol 	const struct device *dev = regmap_get_device(st->map);
53231c24c1eSJean-Baptiste Maneyrol 	int ret;
53331c24c1eSJean-Baptiste Maneyrol 
53431c24c1eSJean-Baptiste Maneyrol 	ret = regulator_disable(st->vdd_supply);
53531c24c1eSJean-Baptiste Maneyrol 	if (ret)
53631c24c1eSJean-Baptiste Maneyrol 		dev_err(dev, "failed to disable vdd error %d\n", ret);
53731c24c1eSJean-Baptiste Maneyrol }
53831c24c1eSJean-Baptiste Maneyrol 
53931c24c1eSJean-Baptiste Maneyrol static void inv_icm42600_disable_vddio_reg(void *_data)
54031c24c1eSJean-Baptiste Maneyrol {
54131c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_state *st = _data;
54231c24c1eSJean-Baptiste Maneyrol 	const struct device *dev = regmap_get_device(st->map);
54331c24c1eSJean-Baptiste Maneyrol 	int ret;
54431c24c1eSJean-Baptiste Maneyrol 
54531c24c1eSJean-Baptiste Maneyrol 	ret = regulator_disable(st->vddio_supply);
54631c24c1eSJean-Baptiste Maneyrol 	if (ret)
54731c24c1eSJean-Baptiste Maneyrol 		dev_err(dev, "failed to disable vddio error %d\n", ret);
54831c24c1eSJean-Baptiste Maneyrol }
54931c24c1eSJean-Baptiste Maneyrol 
55031c24c1eSJean-Baptiste Maneyrol static void inv_icm42600_disable_pm(void *_data)
55131c24c1eSJean-Baptiste Maneyrol {
55231c24c1eSJean-Baptiste Maneyrol 	struct device *dev = _data;
55331c24c1eSJean-Baptiste Maneyrol 
55431c24c1eSJean-Baptiste Maneyrol 	pm_runtime_put_sync(dev);
55531c24c1eSJean-Baptiste Maneyrol 	pm_runtime_disable(dev);
55631c24c1eSJean-Baptiste Maneyrol }
55731c24c1eSJean-Baptiste Maneyrol 
558e5efa104SJean-Baptiste Maneyrol int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
55931c24c1eSJean-Baptiste Maneyrol 			    inv_icm42600_bus_setup bus_setup)
56031c24c1eSJean-Baptiste Maneyrol {
56131c24c1eSJean-Baptiste Maneyrol 	struct device *dev = regmap_get_device(regmap);
56231c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_state *st;
563e5efa104SJean-Baptiste Maneyrol 	struct irq_data *irq_desc;
564e5efa104SJean-Baptiste Maneyrol 	int irq_type;
565e5efa104SJean-Baptiste Maneyrol 	bool open_drain;
56631c24c1eSJean-Baptiste Maneyrol 	int ret;
56731c24c1eSJean-Baptiste Maneyrol 
56831c24c1eSJean-Baptiste Maneyrol 	if (chip < 0 || chip >= INV_CHIP_NB) {
56931c24c1eSJean-Baptiste Maneyrol 		dev_err(dev, "invalid chip = %d\n", chip);
57031c24c1eSJean-Baptiste Maneyrol 		return -ENODEV;
57131c24c1eSJean-Baptiste Maneyrol 	}
57231c24c1eSJean-Baptiste Maneyrol 
573e5efa104SJean-Baptiste Maneyrol 	/* get irq properties, set trigger falling by default */
574e5efa104SJean-Baptiste Maneyrol 	irq_desc = irq_get_irq_data(irq);
575e5efa104SJean-Baptiste Maneyrol 	if (!irq_desc) {
576e5efa104SJean-Baptiste Maneyrol 		dev_err(dev, "could not find IRQ %d\n", irq);
577e5efa104SJean-Baptiste Maneyrol 		return -EINVAL;
578e5efa104SJean-Baptiste Maneyrol 	}
579e5efa104SJean-Baptiste Maneyrol 
580e5efa104SJean-Baptiste Maneyrol 	irq_type = irqd_get_trigger_type(irq_desc);
581e5efa104SJean-Baptiste Maneyrol 	if (!irq_type)
582e5efa104SJean-Baptiste Maneyrol 		irq_type = IRQF_TRIGGER_FALLING;
583e5efa104SJean-Baptiste Maneyrol 
584e5efa104SJean-Baptiste Maneyrol 	open_drain = device_property_read_bool(dev, "drive-open-drain");
585e5efa104SJean-Baptiste Maneyrol 
58631c24c1eSJean-Baptiste Maneyrol 	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
58731c24c1eSJean-Baptiste Maneyrol 	if (!st)
58831c24c1eSJean-Baptiste Maneyrol 		return -ENOMEM;
58931c24c1eSJean-Baptiste Maneyrol 
59031c24c1eSJean-Baptiste Maneyrol 	dev_set_drvdata(dev, st);
59131c24c1eSJean-Baptiste Maneyrol 	mutex_init(&st->lock);
59231c24c1eSJean-Baptiste Maneyrol 	st->chip = chip;
59331c24c1eSJean-Baptiste Maneyrol 	st->map = regmap;
59431c24c1eSJean-Baptiste Maneyrol 
59531c24c1eSJean-Baptiste Maneyrol 	ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation);
59631c24c1eSJean-Baptiste Maneyrol 	if (ret) {
59731c24c1eSJean-Baptiste Maneyrol 		dev_err(dev, "failed to retrieve mounting matrix %d\n", ret);
59831c24c1eSJean-Baptiste Maneyrol 		return ret;
59931c24c1eSJean-Baptiste Maneyrol 	}
60031c24c1eSJean-Baptiste Maneyrol 
60131c24c1eSJean-Baptiste Maneyrol 	st->vdd_supply = devm_regulator_get(dev, "vdd");
60231c24c1eSJean-Baptiste Maneyrol 	if (IS_ERR(st->vdd_supply))
60331c24c1eSJean-Baptiste Maneyrol 		return PTR_ERR(st->vdd_supply);
60431c24c1eSJean-Baptiste Maneyrol 
60531c24c1eSJean-Baptiste Maneyrol 	st->vddio_supply = devm_regulator_get(dev, "vddio");
60631c24c1eSJean-Baptiste Maneyrol 	if (IS_ERR(st->vddio_supply))
60731c24c1eSJean-Baptiste Maneyrol 		return PTR_ERR(st->vddio_supply);
60831c24c1eSJean-Baptiste Maneyrol 
60931c24c1eSJean-Baptiste Maneyrol 	ret = regulator_enable(st->vdd_supply);
61031c24c1eSJean-Baptiste Maneyrol 	if (ret)
61131c24c1eSJean-Baptiste Maneyrol 		return ret;
61231c24c1eSJean-Baptiste Maneyrol 	msleep(INV_ICM42600_POWER_UP_TIME_MS);
61331c24c1eSJean-Baptiste Maneyrol 
61431c24c1eSJean-Baptiste Maneyrol 	ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vdd_reg, st);
61531c24c1eSJean-Baptiste Maneyrol 	if (ret)
61631c24c1eSJean-Baptiste Maneyrol 		return ret;
61731c24c1eSJean-Baptiste Maneyrol 
61831c24c1eSJean-Baptiste Maneyrol 	ret = inv_icm42600_enable_regulator_vddio(st);
61931c24c1eSJean-Baptiste Maneyrol 	if (ret)
62031c24c1eSJean-Baptiste Maneyrol 		return ret;
62131c24c1eSJean-Baptiste Maneyrol 
62231c24c1eSJean-Baptiste Maneyrol 	ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vddio_reg, st);
62331c24c1eSJean-Baptiste Maneyrol 	if (ret)
62431c24c1eSJean-Baptiste Maneyrol 		return ret;
62531c24c1eSJean-Baptiste Maneyrol 
62631c24c1eSJean-Baptiste Maneyrol 	/* setup chip registers */
62731c24c1eSJean-Baptiste Maneyrol 	ret = inv_icm42600_setup(st, bus_setup);
62831c24c1eSJean-Baptiste Maneyrol 	if (ret)
62931c24c1eSJean-Baptiste Maneyrol 		return ret;
63031c24c1eSJean-Baptiste Maneyrol 
631ec74ae9fSJean-Baptiste Maneyrol 	ret = inv_icm42600_timestamp_setup(st);
632ec74ae9fSJean-Baptiste Maneyrol 	if (ret)
633ec74ae9fSJean-Baptiste Maneyrol 		return ret;
634ec74ae9fSJean-Baptiste Maneyrol 
6357f85e42aSJean-Baptiste Maneyrol 	ret = inv_icm42600_buffer_init(st);
6367f85e42aSJean-Baptiste Maneyrol 	if (ret)
6377f85e42aSJean-Baptiste Maneyrol 		return ret;
6387f85e42aSJean-Baptiste Maneyrol 
639a095fadbSJean-Baptiste Maneyrol 	st->indio_gyro = inv_icm42600_gyro_init(st);
640a095fadbSJean-Baptiste Maneyrol 	if (IS_ERR(st->indio_gyro))
641a095fadbSJean-Baptiste Maneyrol 		return PTR_ERR(st->indio_gyro);
642a095fadbSJean-Baptiste Maneyrol 
643a47c1cdcSJean-Baptiste Maneyrol 	st->indio_accel = inv_icm42600_accel_init(st);
644a47c1cdcSJean-Baptiste Maneyrol 	if (IS_ERR(st->indio_accel))
645a47c1cdcSJean-Baptiste Maneyrol 		return PTR_ERR(st->indio_accel);
646a47c1cdcSJean-Baptiste Maneyrol 
647e5efa104SJean-Baptiste Maneyrol 	ret = inv_icm42600_irq_init(st, irq, irq_type, open_drain);
648e5efa104SJean-Baptiste Maneyrol 	if (ret)
649e5efa104SJean-Baptiste Maneyrol 		return ret;
650e5efa104SJean-Baptiste Maneyrol 
65131c24c1eSJean-Baptiste Maneyrol 	/* setup runtime power management */
65231c24c1eSJean-Baptiste Maneyrol 	ret = pm_runtime_set_active(dev);
65331c24c1eSJean-Baptiste Maneyrol 	if (ret)
65431c24c1eSJean-Baptiste Maneyrol 		return ret;
65531c24c1eSJean-Baptiste Maneyrol 	pm_runtime_get_noresume(dev);
65631c24c1eSJean-Baptiste Maneyrol 	pm_runtime_enable(dev);
65731c24c1eSJean-Baptiste Maneyrol 	pm_runtime_set_autosuspend_delay(dev, INV_ICM42600_SUSPEND_DELAY_MS);
65831c24c1eSJean-Baptiste Maneyrol 	pm_runtime_use_autosuspend(dev);
65931c24c1eSJean-Baptiste Maneyrol 	pm_runtime_put(dev);
66031c24c1eSJean-Baptiste Maneyrol 
66131c24c1eSJean-Baptiste Maneyrol 	return devm_add_action_or_reset(dev, inv_icm42600_disable_pm, dev);
66231c24c1eSJean-Baptiste Maneyrol }
66331c24c1eSJean-Baptiste Maneyrol EXPORT_SYMBOL_GPL(inv_icm42600_core_probe);
66431c24c1eSJean-Baptiste Maneyrol 
66531c24c1eSJean-Baptiste Maneyrol /*
66631c24c1eSJean-Baptiste Maneyrol  * Suspend saves sensors state and turns everything off.
66731c24c1eSJean-Baptiste Maneyrol  * Check first if runtime suspend has not already done the job.
66831c24c1eSJean-Baptiste Maneyrol  */
66931c24c1eSJean-Baptiste Maneyrol static int __maybe_unused inv_icm42600_suspend(struct device *dev)
67031c24c1eSJean-Baptiste Maneyrol {
67131c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_state *st = dev_get_drvdata(dev);
67231c24c1eSJean-Baptiste Maneyrol 	int ret;
67331c24c1eSJean-Baptiste Maneyrol 
67431c24c1eSJean-Baptiste Maneyrol 	mutex_lock(&st->lock);
67531c24c1eSJean-Baptiste Maneyrol 
67631c24c1eSJean-Baptiste Maneyrol 	st->suspended.gyro = st->conf.gyro.mode;
67731c24c1eSJean-Baptiste Maneyrol 	st->suspended.accel = st->conf.accel.mode;
67831c24c1eSJean-Baptiste Maneyrol 	st->suspended.temp = st->conf.temp_en;
67931c24c1eSJean-Baptiste Maneyrol 	if (pm_runtime_suspended(dev)) {
68031c24c1eSJean-Baptiste Maneyrol 		ret = 0;
68131c24c1eSJean-Baptiste Maneyrol 		goto out_unlock;
68231c24c1eSJean-Baptiste Maneyrol 	}
68331c24c1eSJean-Baptiste Maneyrol 
6847f85e42aSJean-Baptiste Maneyrol 	/* disable FIFO data streaming */
6857f85e42aSJean-Baptiste Maneyrol 	if (st->fifo.on) {
6867f85e42aSJean-Baptiste Maneyrol 		ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
6877f85e42aSJean-Baptiste Maneyrol 				   INV_ICM42600_FIFO_CONFIG_BYPASS);
6887f85e42aSJean-Baptiste Maneyrol 		if (ret)
6897f85e42aSJean-Baptiste Maneyrol 			goto out_unlock;
6907f85e42aSJean-Baptiste Maneyrol 	}
6917f85e42aSJean-Baptiste Maneyrol 
69231c24c1eSJean-Baptiste Maneyrol 	ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
69331c24c1eSJean-Baptiste Maneyrol 					 INV_ICM42600_SENSOR_MODE_OFF, false,
69431c24c1eSJean-Baptiste Maneyrol 					 NULL);
69531c24c1eSJean-Baptiste Maneyrol 	if (ret)
69631c24c1eSJean-Baptiste Maneyrol 		goto out_unlock;
69731c24c1eSJean-Baptiste Maneyrol 
69831c24c1eSJean-Baptiste Maneyrol 	regulator_disable(st->vddio_supply);
69931c24c1eSJean-Baptiste Maneyrol 
70031c24c1eSJean-Baptiste Maneyrol out_unlock:
70131c24c1eSJean-Baptiste Maneyrol 	mutex_unlock(&st->lock);
70231c24c1eSJean-Baptiste Maneyrol 	return ret;
70331c24c1eSJean-Baptiste Maneyrol }
70431c24c1eSJean-Baptiste Maneyrol 
70531c24c1eSJean-Baptiste Maneyrol /*
70631c24c1eSJean-Baptiste Maneyrol  * System resume gets the system back on and restores the sensors state.
70731c24c1eSJean-Baptiste Maneyrol  * Manually put runtime power management in system active state.
70831c24c1eSJean-Baptiste Maneyrol  */
70931c24c1eSJean-Baptiste Maneyrol static int __maybe_unused inv_icm42600_resume(struct device *dev)
71031c24c1eSJean-Baptiste Maneyrol {
71131c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_state *st = dev_get_drvdata(dev);
71231c24c1eSJean-Baptiste Maneyrol 	int ret;
71331c24c1eSJean-Baptiste Maneyrol 
71431c24c1eSJean-Baptiste Maneyrol 	mutex_lock(&st->lock);
71531c24c1eSJean-Baptiste Maneyrol 
71631c24c1eSJean-Baptiste Maneyrol 	ret = inv_icm42600_enable_regulator_vddio(st);
71731c24c1eSJean-Baptiste Maneyrol 	if (ret)
71831c24c1eSJean-Baptiste Maneyrol 		goto out_unlock;
71931c24c1eSJean-Baptiste Maneyrol 
72031c24c1eSJean-Baptiste Maneyrol 	pm_runtime_disable(dev);
72131c24c1eSJean-Baptiste Maneyrol 	pm_runtime_set_active(dev);
72231c24c1eSJean-Baptiste Maneyrol 	pm_runtime_enable(dev);
72331c24c1eSJean-Baptiste Maneyrol 
72431c24c1eSJean-Baptiste Maneyrol 	/* restore sensors state */
72531c24c1eSJean-Baptiste Maneyrol 	ret = inv_icm42600_set_pwr_mgmt0(st, st->suspended.gyro,
72631c24c1eSJean-Baptiste Maneyrol 					 st->suspended.accel,
72731c24c1eSJean-Baptiste Maneyrol 					 st->suspended.temp, NULL);
72831c24c1eSJean-Baptiste Maneyrol 	if (ret)
72931c24c1eSJean-Baptiste Maneyrol 		goto out_unlock;
73031c24c1eSJean-Baptiste Maneyrol 
7317f85e42aSJean-Baptiste Maneyrol 	/* restore FIFO data streaming */
7327f85e42aSJean-Baptiste Maneyrol 	if (st->fifo.on)
7337f85e42aSJean-Baptiste Maneyrol 		ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
7347f85e42aSJean-Baptiste Maneyrol 				   INV_ICM42600_FIFO_CONFIG_STREAM);
7357f85e42aSJean-Baptiste Maneyrol 
73631c24c1eSJean-Baptiste Maneyrol out_unlock:
73731c24c1eSJean-Baptiste Maneyrol 	mutex_unlock(&st->lock);
73831c24c1eSJean-Baptiste Maneyrol 	return ret;
73931c24c1eSJean-Baptiste Maneyrol }
74031c24c1eSJean-Baptiste Maneyrol 
74131c24c1eSJean-Baptiste Maneyrol /* Runtime suspend will turn off sensors that are enabled by iio devices. */
74231c24c1eSJean-Baptiste Maneyrol static int __maybe_unused inv_icm42600_runtime_suspend(struct device *dev)
74331c24c1eSJean-Baptiste Maneyrol {
74431c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_state *st = dev_get_drvdata(dev);
74531c24c1eSJean-Baptiste Maneyrol 	int ret;
74631c24c1eSJean-Baptiste Maneyrol 
74731c24c1eSJean-Baptiste Maneyrol 	mutex_lock(&st->lock);
74831c24c1eSJean-Baptiste Maneyrol 
74931c24c1eSJean-Baptiste Maneyrol 	/* disable all sensors */
75031c24c1eSJean-Baptiste Maneyrol 	ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
75131c24c1eSJean-Baptiste Maneyrol 					 INV_ICM42600_SENSOR_MODE_OFF, false,
75231c24c1eSJean-Baptiste Maneyrol 					 NULL);
75331c24c1eSJean-Baptiste Maneyrol 	if (ret)
75431c24c1eSJean-Baptiste Maneyrol 		goto error_unlock;
75531c24c1eSJean-Baptiste Maneyrol 
75631c24c1eSJean-Baptiste Maneyrol 	regulator_disable(st->vddio_supply);
75731c24c1eSJean-Baptiste Maneyrol 
75831c24c1eSJean-Baptiste Maneyrol error_unlock:
75931c24c1eSJean-Baptiste Maneyrol 	mutex_unlock(&st->lock);
76031c24c1eSJean-Baptiste Maneyrol 	return ret;
76131c24c1eSJean-Baptiste Maneyrol }
76231c24c1eSJean-Baptiste Maneyrol 
76331c24c1eSJean-Baptiste Maneyrol /* Sensors are enabled by iio devices, no need to turn them back on here. */
76431c24c1eSJean-Baptiste Maneyrol static int __maybe_unused inv_icm42600_runtime_resume(struct device *dev)
76531c24c1eSJean-Baptiste Maneyrol {
76631c24c1eSJean-Baptiste Maneyrol 	struct inv_icm42600_state *st = dev_get_drvdata(dev);
76731c24c1eSJean-Baptiste Maneyrol 	int ret;
76831c24c1eSJean-Baptiste Maneyrol 
76931c24c1eSJean-Baptiste Maneyrol 	mutex_lock(&st->lock);
77031c24c1eSJean-Baptiste Maneyrol 
77131c24c1eSJean-Baptiste Maneyrol 	ret = inv_icm42600_enable_regulator_vddio(st);
77231c24c1eSJean-Baptiste Maneyrol 
77331c24c1eSJean-Baptiste Maneyrol 	mutex_unlock(&st->lock);
77431c24c1eSJean-Baptiste Maneyrol 	return ret;
77531c24c1eSJean-Baptiste Maneyrol }
77631c24c1eSJean-Baptiste Maneyrol 
77731c24c1eSJean-Baptiste Maneyrol const struct dev_pm_ops inv_icm42600_pm_ops = {
77831c24c1eSJean-Baptiste Maneyrol 	SET_SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume)
77931c24c1eSJean-Baptiste Maneyrol 	SET_RUNTIME_PM_OPS(inv_icm42600_runtime_suspend,
78031c24c1eSJean-Baptiste Maneyrol 			   inv_icm42600_runtime_resume, NULL)
78131c24c1eSJean-Baptiste Maneyrol };
78231c24c1eSJean-Baptiste Maneyrol EXPORT_SYMBOL_GPL(inv_icm42600_pm_ops);
78331c24c1eSJean-Baptiste Maneyrol 
78431c24c1eSJean-Baptiste Maneyrol MODULE_AUTHOR("InvenSense, Inc.");
78531c24c1eSJean-Baptiste Maneyrol MODULE_DESCRIPTION("InvenSense ICM-426xx device driver");
78631c24c1eSJean-Baptiste Maneyrol MODULE_LICENSE("GPL");
787