xref: /openbmc/linux/drivers/iio/imu/bno055/bno055.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
14aefe1c2SAndrea Merello // SPDX-License-Identifier: GPL-2.0
24aefe1c2SAndrea Merello /*
34aefe1c2SAndrea Merello  * IIO driver for Bosch BNO055 IMU
44aefe1c2SAndrea Merello  *
54aefe1c2SAndrea Merello  * Copyright (C) 2021-2022 Istituto Italiano di Tecnologia
64aefe1c2SAndrea Merello  * Electronic Design Laboratory
74aefe1c2SAndrea Merello  * Written by Andrea Merello <andrea.merello@iit.it>
84aefe1c2SAndrea Merello  *
94aefe1c2SAndrea Merello  * Portions of this driver are taken from the BNO055 driver patch
104aefe1c2SAndrea Merello  * from Vlad Dogaru which is Copyright (c) 2016, Intel Corporation.
114aefe1c2SAndrea Merello  *
124aefe1c2SAndrea Merello  * This driver is also based on BMI160 driver, which is:
134aefe1c2SAndrea Merello  *	Copyright (c) 2016, Intel Corporation.
144aefe1c2SAndrea Merello  *	Copyright (c) 2019, Martin Kelly.
154aefe1c2SAndrea Merello  */
164aefe1c2SAndrea Merello 
174aefe1c2SAndrea Merello #include <linux/bitfield.h>
184aefe1c2SAndrea Merello #include <linux/bitmap.h>
194aefe1c2SAndrea Merello #include <linux/clk.h>
204aefe1c2SAndrea Merello #include <linux/debugfs.h>
214aefe1c2SAndrea Merello #include <linux/device.h>
224aefe1c2SAndrea Merello #include <linux/firmware.h>
234aefe1c2SAndrea Merello #include <linux/gpio/consumer.h>
244aefe1c2SAndrea Merello #include <linux/module.h>
254aefe1c2SAndrea Merello #include <linux/mutex.h>
264aefe1c2SAndrea Merello #include <linux/regmap.h>
274aefe1c2SAndrea Merello #include <linux/util_macros.h>
284aefe1c2SAndrea Merello 
294aefe1c2SAndrea Merello #include <linux/iio/buffer.h>
304aefe1c2SAndrea Merello #include <linux/iio/iio.h>
314aefe1c2SAndrea Merello #include <linux/iio/sysfs.h>
324aefe1c2SAndrea Merello #include <linux/iio/trigger_consumer.h>
334aefe1c2SAndrea Merello #include <linux/iio/triggered_buffer.h>
344aefe1c2SAndrea Merello 
354aefe1c2SAndrea Merello #include "bno055.h"
364aefe1c2SAndrea Merello 
374aefe1c2SAndrea Merello #define BNO055_FW_UID_FMT "bno055-caldata-%*phN.dat"
384aefe1c2SAndrea Merello #define BNO055_FW_GENERIC_NAME "bno055-caldata.dat"
394aefe1c2SAndrea Merello 
404aefe1c2SAndrea Merello /* common registers */
414aefe1c2SAndrea Merello #define BNO055_PAGESEL_REG		0x7
424aefe1c2SAndrea Merello 
434aefe1c2SAndrea Merello /* page 0 registers */
444aefe1c2SAndrea Merello #define BNO055_CHIP_ID_REG		0x0
454aefe1c2SAndrea Merello #define BNO055_CHIP_ID_MAGIC 0xA0
464aefe1c2SAndrea Merello #define BNO055_SW_REV_LSB_REG		0x4
474aefe1c2SAndrea Merello #define BNO055_SW_REV_MSB_REG		0x5
484aefe1c2SAndrea Merello #define BNO055_ACC_DATA_X_LSB_REG	0x8
494aefe1c2SAndrea Merello #define BNO055_ACC_DATA_Y_LSB_REG	0xA
504aefe1c2SAndrea Merello #define BNO055_ACC_DATA_Z_LSB_REG	0xC
514aefe1c2SAndrea Merello #define BNO055_MAG_DATA_X_LSB_REG	0xE
524aefe1c2SAndrea Merello #define BNO055_MAG_DATA_Y_LSB_REG	0x10
534aefe1c2SAndrea Merello #define BNO055_MAG_DATA_Z_LSB_REG	0x12
544aefe1c2SAndrea Merello #define BNO055_GYR_DATA_X_LSB_REG	0x14
554aefe1c2SAndrea Merello #define BNO055_GYR_DATA_Y_LSB_REG	0x16
564aefe1c2SAndrea Merello #define BNO055_GYR_DATA_Z_LSB_REG	0x18
574aefe1c2SAndrea Merello #define BNO055_EUL_DATA_X_LSB_REG	0x1A
584aefe1c2SAndrea Merello #define BNO055_EUL_DATA_Y_LSB_REG	0x1C
594aefe1c2SAndrea Merello #define BNO055_EUL_DATA_Z_LSB_REG	0x1E
604aefe1c2SAndrea Merello #define BNO055_QUAT_DATA_W_LSB_REG	0x20
614aefe1c2SAndrea Merello #define BNO055_LIA_DATA_X_LSB_REG	0x28
624aefe1c2SAndrea Merello #define BNO055_LIA_DATA_Y_LSB_REG	0x2A
634aefe1c2SAndrea Merello #define BNO055_LIA_DATA_Z_LSB_REG	0x2C
644aefe1c2SAndrea Merello #define BNO055_GRAVITY_DATA_X_LSB_REG	0x2E
654aefe1c2SAndrea Merello #define BNO055_GRAVITY_DATA_Y_LSB_REG	0x30
664aefe1c2SAndrea Merello #define BNO055_GRAVITY_DATA_Z_LSB_REG	0x32
674aefe1c2SAndrea Merello #define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2)
684aefe1c2SAndrea Merello #define BNO055_TEMP_REG			0x34
694aefe1c2SAndrea Merello #define BNO055_CALIB_STAT_REG		0x35
704aefe1c2SAndrea Merello #define BNO055_CALIB_STAT_MAGN_SHIFT 0
714aefe1c2SAndrea Merello #define BNO055_CALIB_STAT_ACCEL_SHIFT 2
724aefe1c2SAndrea Merello #define BNO055_CALIB_STAT_GYRO_SHIFT 4
734aefe1c2SAndrea Merello #define BNO055_CALIB_STAT_SYS_SHIFT 6
744aefe1c2SAndrea Merello #define BNO055_SYS_ERR_REG		0x3A
754aefe1c2SAndrea Merello #define BNO055_POWER_MODE_REG		0x3E
764aefe1c2SAndrea Merello #define BNO055_POWER_MODE_NORMAL 0
774aefe1c2SAndrea Merello #define BNO055_SYS_TRIGGER_REG		0x3F
784aefe1c2SAndrea Merello #define BNO055_SYS_TRIGGER_RST_SYS BIT(5)
794aefe1c2SAndrea Merello #define BNO055_SYS_TRIGGER_CLK_SEL BIT(7)
804aefe1c2SAndrea Merello #define BNO055_OPR_MODE_REG		0x3D
814aefe1c2SAndrea Merello #define BNO055_OPR_MODE_CONFIG 0x0
824aefe1c2SAndrea Merello #define BNO055_OPR_MODE_AMG 0x7
834aefe1c2SAndrea Merello #define BNO055_OPR_MODE_FUSION_FMC_OFF 0xB
844aefe1c2SAndrea Merello #define BNO055_OPR_MODE_FUSION 0xC
854aefe1c2SAndrea Merello #define BNO055_UNIT_SEL_REG		0x3B
864aefe1c2SAndrea Merello /* Android orientation mode means: pitch value decreases turning clockwise */
874aefe1c2SAndrea Merello #define BNO055_UNIT_SEL_ANDROID BIT(7)
884aefe1c2SAndrea Merello #define BNO055_UNIT_SEL_GYR_RPS BIT(1)
894aefe1c2SAndrea Merello #define BNO055_CALDATA_START		0x55
904aefe1c2SAndrea Merello #define BNO055_CALDATA_END		0x6A
914aefe1c2SAndrea Merello #define BNO055_CALDATA_LEN 22
924aefe1c2SAndrea Merello 
934aefe1c2SAndrea Merello /*
944aefe1c2SAndrea Merello  * The difference in address between the register that contains the
954aefe1c2SAndrea Merello  * value and the register that contains the offset.  This applies for
964aefe1c2SAndrea Merello  * accel, gyro and magn channels.
974aefe1c2SAndrea Merello  */
984aefe1c2SAndrea Merello #define BNO055_REG_OFFSET_ADDR		0x4D
994aefe1c2SAndrea Merello 
1004aefe1c2SAndrea Merello /* page 1 registers */
1014aefe1c2SAndrea Merello #define BNO055_PG1(x) ((x) | 0x80)
1024aefe1c2SAndrea Merello #define BNO055_ACC_CONFIG_REG		BNO055_PG1(0x8)
1034aefe1c2SAndrea Merello #define BNO055_ACC_CONFIG_LPF_MASK GENMASK(4, 2)
1044aefe1c2SAndrea Merello #define BNO055_ACC_CONFIG_RANGE_MASK GENMASK(1, 0)
1054aefe1c2SAndrea Merello #define BNO055_MAG_CONFIG_REG		BNO055_PG1(0x9)
1064aefe1c2SAndrea Merello #define BNO055_MAG_CONFIG_HIGHACCURACY 0x18
1074aefe1c2SAndrea Merello #define BNO055_MAG_CONFIG_ODR_MASK GENMASK(2, 0)
1084aefe1c2SAndrea Merello #define BNO055_GYR_CONFIG_REG		BNO055_PG1(0xA)
1094aefe1c2SAndrea Merello #define BNO055_GYR_CONFIG_RANGE_MASK GENMASK(2, 0)
1104aefe1c2SAndrea Merello #define BNO055_GYR_CONFIG_LPF_MASK GENMASK(5, 3)
1114aefe1c2SAndrea Merello #define BNO055_GYR_AM_SET_REG		BNO055_PG1(0x1F)
1124aefe1c2SAndrea Merello #define BNO055_UID_LOWER_REG		BNO055_PG1(0x50)
1134aefe1c2SAndrea Merello #define BNO055_UID_HIGHER_REG		BNO055_PG1(0x5F)
1144aefe1c2SAndrea Merello #define BNO055_UID_LEN 16
1154aefe1c2SAndrea Merello 
1164aefe1c2SAndrea Merello struct bno055_sysfs_attr {
1174aefe1c2SAndrea Merello 	int *vals;
1184aefe1c2SAndrea Merello 	int len;
1194aefe1c2SAndrea Merello 	int *fusion_vals;
1204aefe1c2SAndrea Merello 	int *hw_xlate;
1214aefe1c2SAndrea Merello 	int type;
1224aefe1c2SAndrea Merello };
1234aefe1c2SAndrea Merello 
1244aefe1c2SAndrea Merello static int bno055_acc_lpf_vals[] = {
1254aefe1c2SAndrea Merello 	7, 810000, 15, 630000, 31, 250000, 62, 500000,
1264aefe1c2SAndrea Merello 	125, 0, 250, 0, 500, 0, 1000, 0,
1274aefe1c2SAndrea Merello };
1284aefe1c2SAndrea Merello 
1294aefe1c2SAndrea Merello static struct bno055_sysfs_attr bno055_acc_lpf = {
1304aefe1c2SAndrea Merello 	.vals = bno055_acc_lpf_vals,
1314aefe1c2SAndrea Merello 	.len = ARRAY_SIZE(bno055_acc_lpf_vals),
1324aefe1c2SAndrea Merello 	.fusion_vals = (int[]){62, 500000},
1334aefe1c2SAndrea Merello 	.type = IIO_VAL_INT_PLUS_MICRO,
1344aefe1c2SAndrea Merello };
1354aefe1c2SAndrea Merello 
1364aefe1c2SAndrea Merello static int bno055_acc_range_vals[] = {
1374aefe1c2SAndrea Merello   /* G:    2,    4,    8,    16 */
1384aefe1c2SAndrea Merello 	1962, 3924, 7848, 15696
1394aefe1c2SAndrea Merello };
1404aefe1c2SAndrea Merello 
1414aefe1c2SAndrea Merello static struct bno055_sysfs_attr bno055_acc_range = {
1424aefe1c2SAndrea Merello 	.vals = bno055_acc_range_vals,
1434aefe1c2SAndrea Merello 	.len = ARRAY_SIZE(bno055_acc_range_vals),
1444aefe1c2SAndrea Merello 	.fusion_vals = (int[]){3924}, /* 4G */
1454aefe1c2SAndrea Merello 	.type = IIO_VAL_INT,
1464aefe1c2SAndrea Merello };
1474aefe1c2SAndrea Merello 
1484aefe1c2SAndrea Merello /*
1494aefe1c2SAndrea Merello  * Theoretically the IMU should return data in a given (i.e. fixed) unit
1504aefe1c2SAndrea Merello  * regardless of the range setting. This happens for the accelerometer, but not
1514aefe1c2SAndrea Merello  * for the gyroscope; the gyroscope range setting affects the scale.
1524aefe1c2SAndrea Merello  * This is probably due to this[0] bug.
1534aefe1c2SAndrea Merello  * For this reason we map the internal range setting onto the standard IIO scale
1544aefe1c2SAndrea Merello  * attribute for gyro.
1554aefe1c2SAndrea Merello  * Since the bug[0] may be fixed in future, we check for the IMU FW version and
1564aefe1c2SAndrea Merello  * eventually warn the user.
1574aefe1c2SAndrea Merello  * Currently we just don't care about "range" attributes for gyro.
1584aefe1c2SAndrea Merello  *
1594aefe1c2SAndrea Merello  * [0]  https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BNO055-Wrong-sensitivity-resolution-in-datasheet/td-p/10266
1604aefe1c2SAndrea Merello  */
1614aefe1c2SAndrea Merello 
1624aefe1c2SAndrea Merello /*
1634aefe1c2SAndrea Merello  * dps = hwval * (dps_range/2^15)
1644aefe1c2SAndrea Merello  * rps = hwval * (rps_range/2^15)
1654aefe1c2SAndrea Merello  *     = hwval * (dps_range/(2^15 * k))
1664aefe1c2SAndrea Merello  * where k is rad-to-deg factor
1674aefe1c2SAndrea Merello  */
1684aefe1c2SAndrea Merello static int bno055_gyr_scale_vals[] = {
1694aefe1c2SAndrea Merello 	125, 1877467, 250, 1877467, 500, 1877467,
1704aefe1c2SAndrea Merello 	1000, 1877467, 2000, 1877467,
1714aefe1c2SAndrea Merello };
1724aefe1c2SAndrea Merello 
1734aefe1c2SAndrea Merello static struct bno055_sysfs_attr bno055_gyr_scale = {
1744aefe1c2SAndrea Merello 	.vals = bno055_gyr_scale_vals,
1754aefe1c2SAndrea Merello 	.len = ARRAY_SIZE(bno055_gyr_scale_vals),
1764aefe1c2SAndrea Merello 	.fusion_vals = (int[]){1, 900},
1774aefe1c2SAndrea Merello 	.hw_xlate = (int[]){4, 3, 2, 1, 0},
1784aefe1c2SAndrea Merello 	.type = IIO_VAL_FRACTIONAL,
1794aefe1c2SAndrea Merello };
1804aefe1c2SAndrea Merello 
1814aefe1c2SAndrea Merello static int bno055_gyr_lpf_vals[] = {12, 23, 32, 47, 64, 116, 230, 523};
1824aefe1c2SAndrea Merello static struct bno055_sysfs_attr bno055_gyr_lpf = {
1834aefe1c2SAndrea Merello 	.vals = bno055_gyr_lpf_vals,
1844aefe1c2SAndrea Merello 	.len = ARRAY_SIZE(bno055_gyr_lpf_vals),
1854aefe1c2SAndrea Merello 	.fusion_vals = (int[]){32},
1864aefe1c2SAndrea Merello 	.hw_xlate = (int[]){5, 4, 7, 3, 6, 2, 1, 0},
1874aefe1c2SAndrea Merello 	.type = IIO_VAL_INT,
1884aefe1c2SAndrea Merello };
1894aefe1c2SAndrea Merello 
1904aefe1c2SAndrea Merello static int bno055_mag_odr_vals[] = {2, 6, 8, 10, 15, 20, 25, 30};
1914aefe1c2SAndrea Merello static struct bno055_sysfs_attr bno055_mag_odr = {
1924aefe1c2SAndrea Merello 	.vals = bno055_mag_odr_vals,
1934aefe1c2SAndrea Merello 	.len =  ARRAY_SIZE(bno055_mag_odr_vals),
1944aefe1c2SAndrea Merello 	.fusion_vals = (int[]){20},
1954aefe1c2SAndrea Merello 	.type = IIO_VAL_INT,
1964aefe1c2SAndrea Merello };
1974aefe1c2SAndrea Merello 
1984aefe1c2SAndrea Merello struct bno055_priv {
1994aefe1c2SAndrea Merello 	struct regmap *regmap;
2004aefe1c2SAndrea Merello 	struct device *dev;
2014aefe1c2SAndrea Merello 	struct clk *clk;
2024aefe1c2SAndrea Merello 	int operation_mode;
2034aefe1c2SAndrea Merello 	int xfer_burst_break_thr;
2044aefe1c2SAndrea Merello 	struct mutex lock;
2054aefe1c2SAndrea Merello 	u8 uid[BNO055_UID_LEN];
2064aefe1c2SAndrea Merello 	struct gpio_desc *reset_gpio;
2074aefe1c2SAndrea Merello 	bool sw_reset;
2084aefe1c2SAndrea Merello 	struct {
2094aefe1c2SAndrea Merello 		__le16 chans[BNO055_SCAN_CH_COUNT];
2104aefe1c2SAndrea Merello 		s64 timestamp __aligned(8);
2114aefe1c2SAndrea Merello 	} buf;
2124aefe1c2SAndrea Merello 	struct dentry *debugfs;
2134aefe1c2SAndrea Merello };
2144aefe1c2SAndrea Merello 
bno055_regmap_volatile(struct device * dev,unsigned int reg)2154aefe1c2SAndrea Merello static bool bno055_regmap_volatile(struct device *dev, unsigned int reg)
2164aefe1c2SAndrea Merello {
2174aefe1c2SAndrea Merello 	/* data and status registers */
2184aefe1c2SAndrea Merello 	if (reg >= BNO055_ACC_DATA_X_LSB_REG && reg <= BNO055_SYS_ERR_REG)
2194aefe1c2SAndrea Merello 		return true;
2204aefe1c2SAndrea Merello 
2214aefe1c2SAndrea Merello 	/* when in fusion mode, config is updated by chip */
2224aefe1c2SAndrea Merello 	if (reg == BNO055_MAG_CONFIG_REG ||
2234aefe1c2SAndrea Merello 	    reg == BNO055_ACC_CONFIG_REG ||
2244aefe1c2SAndrea Merello 	    reg == BNO055_GYR_CONFIG_REG)
2254aefe1c2SAndrea Merello 		return true;
2264aefe1c2SAndrea Merello 
2274aefe1c2SAndrea Merello 	/* calibration data may be updated by the IMU */
2284aefe1c2SAndrea Merello 	if (reg >= BNO055_CALDATA_START && reg <= BNO055_CALDATA_END)
2294aefe1c2SAndrea Merello 		return true;
2304aefe1c2SAndrea Merello 
2314aefe1c2SAndrea Merello 	return false;
2324aefe1c2SAndrea Merello }
2334aefe1c2SAndrea Merello 
bno055_regmap_readable(struct device * dev,unsigned int reg)2344aefe1c2SAndrea Merello static bool bno055_regmap_readable(struct device *dev, unsigned int reg)
2354aefe1c2SAndrea Merello {
2364aefe1c2SAndrea Merello 	/* unnamed PG0 reserved areas */
2374aefe1c2SAndrea Merello 	if ((reg < BNO055_PG1(0) && reg > BNO055_CALDATA_END) ||
2384aefe1c2SAndrea Merello 	    reg == 0x3C)
2394aefe1c2SAndrea Merello 		return false;
2404aefe1c2SAndrea Merello 
2414aefe1c2SAndrea Merello 	/* unnamed PG1 reserved areas */
2424aefe1c2SAndrea Merello 	if (reg > BNO055_PG1(BNO055_UID_HIGHER_REG) ||
2434aefe1c2SAndrea Merello 	    (reg < BNO055_PG1(BNO055_UID_LOWER_REG) && reg > BNO055_PG1(BNO055_GYR_AM_SET_REG)) ||
2444aefe1c2SAndrea Merello 	    reg == BNO055_PG1(0xE) ||
2454aefe1c2SAndrea Merello 	    (reg < BNO055_PG1(BNO055_PAGESEL_REG) && reg >= BNO055_PG1(0x0)))
2464aefe1c2SAndrea Merello 		return false;
2474aefe1c2SAndrea Merello 	return true;
2484aefe1c2SAndrea Merello }
2494aefe1c2SAndrea Merello 
bno055_regmap_writeable(struct device * dev,unsigned int reg)2504aefe1c2SAndrea Merello static bool bno055_regmap_writeable(struct device *dev, unsigned int reg)
2514aefe1c2SAndrea Merello {
2524aefe1c2SAndrea Merello 	/*
2534aefe1c2SAndrea Merello 	 * Unreadable registers are indeed reserved; there are no WO regs
2544aefe1c2SAndrea Merello 	 * (except for a single bit in SYS_TRIGGER register)
2554aefe1c2SAndrea Merello 	 */
2564aefe1c2SAndrea Merello 	if (!bno055_regmap_readable(dev, reg))
2574aefe1c2SAndrea Merello 		return false;
2584aefe1c2SAndrea Merello 
2594aefe1c2SAndrea Merello 	/* data and status registers */
2604aefe1c2SAndrea Merello 	if (reg >= BNO055_ACC_DATA_X_LSB_REG && reg <= BNO055_SYS_ERR_REG)
2614aefe1c2SAndrea Merello 		return false;
2624aefe1c2SAndrea Merello 
2634aefe1c2SAndrea Merello 	/* ID areas */
2644aefe1c2SAndrea Merello 	if (reg < BNO055_PAGESEL_REG ||
2654aefe1c2SAndrea Merello 	    (reg <= BNO055_UID_HIGHER_REG && reg >= BNO055_UID_LOWER_REG))
2664aefe1c2SAndrea Merello 		return false;
2674aefe1c2SAndrea Merello 
2684aefe1c2SAndrea Merello 	return true;
2694aefe1c2SAndrea Merello }
2704aefe1c2SAndrea Merello 
2714aefe1c2SAndrea Merello static const struct regmap_range_cfg bno055_regmap_ranges[] = {
2724aefe1c2SAndrea Merello 	{
2734aefe1c2SAndrea Merello 		.range_min = 0,
2744aefe1c2SAndrea Merello 		.range_max = 0x7f * 2,
2754aefe1c2SAndrea Merello 		.selector_reg = BNO055_PAGESEL_REG,
2764aefe1c2SAndrea Merello 		.selector_mask = GENMASK(7, 0),
2774aefe1c2SAndrea Merello 		.selector_shift = 0,
2784aefe1c2SAndrea Merello 		.window_start = 0,
2794aefe1c2SAndrea Merello 		.window_len = 0x80,
2804aefe1c2SAndrea Merello 	},
2814aefe1c2SAndrea Merello };
2824aefe1c2SAndrea Merello 
2834aefe1c2SAndrea Merello const struct regmap_config bno055_regmap_config = {
2844aefe1c2SAndrea Merello 	.name = "bno055",
2854aefe1c2SAndrea Merello 	.reg_bits = 8,
2864aefe1c2SAndrea Merello 	.val_bits = 8,
2874aefe1c2SAndrea Merello 	.ranges = bno055_regmap_ranges,
2884aefe1c2SAndrea Merello 	.num_ranges = 1,
2894aefe1c2SAndrea Merello 	.volatile_reg = bno055_regmap_volatile,
2904aefe1c2SAndrea Merello 	.max_register = 0x80 * 2,
2914aefe1c2SAndrea Merello 	.writeable_reg = bno055_regmap_writeable,
2924aefe1c2SAndrea Merello 	.readable_reg = bno055_regmap_readable,
2934aefe1c2SAndrea Merello 	.cache_type = REGCACHE_RBTREE,
2944aefe1c2SAndrea Merello };
2954aefe1c2SAndrea Merello EXPORT_SYMBOL_NS_GPL(bno055_regmap_config, IIO_BNO055);
2964aefe1c2SAndrea Merello 
2974aefe1c2SAndrea Merello /* must be called in configuration mode */
bno055_calibration_load(struct bno055_priv * priv,const u8 * data,int len)2984aefe1c2SAndrea Merello static int bno055_calibration_load(struct bno055_priv *priv, const u8 *data, int len)
2994aefe1c2SAndrea Merello {
3004aefe1c2SAndrea Merello 	if (len != BNO055_CALDATA_LEN) {
3014aefe1c2SAndrea Merello 		dev_dbg(priv->dev, "Invalid calibration file size %d (expected %d)",
3024aefe1c2SAndrea Merello 			len, BNO055_CALDATA_LEN);
3034aefe1c2SAndrea Merello 		return -EINVAL;
3044aefe1c2SAndrea Merello 	}
3054aefe1c2SAndrea Merello 
3064aefe1c2SAndrea Merello 	dev_dbg(priv->dev, "loading cal data: %*ph", BNO055_CALDATA_LEN, data);
3074aefe1c2SAndrea Merello 	return regmap_bulk_write(priv->regmap, BNO055_CALDATA_START,
3084aefe1c2SAndrea Merello 				 data, BNO055_CALDATA_LEN);
3094aefe1c2SAndrea Merello }
3104aefe1c2SAndrea Merello 
bno055_operation_mode_do_set(struct bno055_priv * priv,int operation_mode)3114aefe1c2SAndrea Merello static int bno055_operation_mode_do_set(struct bno055_priv *priv,
3124aefe1c2SAndrea Merello 					int operation_mode)
3134aefe1c2SAndrea Merello {
3144aefe1c2SAndrea Merello 	int ret;
3154aefe1c2SAndrea Merello 
3164aefe1c2SAndrea Merello 	ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG,
3174aefe1c2SAndrea Merello 			   operation_mode);
3184aefe1c2SAndrea Merello 	if (ret)
3194aefe1c2SAndrea Merello 		return ret;
3204aefe1c2SAndrea Merello 
3214aefe1c2SAndrea Merello 	/* Following datasheet specifications: sensor takes 7mS up to 19 mS to switch mode */
3224aefe1c2SAndrea Merello 	msleep(20);
3234aefe1c2SAndrea Merello 
3244aefe1c2SAndrea Merello 	return 0;
3254aefe1c2SAndrea Merello }
3264aefe1c2SAndrea Merello 
bno055_system_reset(struct bno055_priv * priv)3274aefe1c2SAndrea Merello static int bno055_system_reset(struct bno055_priv *priv)
3284aefe1c2SAndrea Merello {
3294aefe1c2SAndrea Merello 	int ret;
3304aefe1c2SAndrea Merello 
3314aefe1c2SAndrea Merello 	if (priv->reset_gpio) {
3324aefe1c2SAndrea Merello 		gpiod_set_value_cansleep(priv->reset_gpio, 0);
3334aefe1c2SAndrea Merello 		usleep_range(5000, 10000);
3344aefe1c2SAndrea Merello 		gpiod_set_value_cansleep(priv->reset_gpio, 1);
3354aefe1c2SAndrea Merello 	} else if (priv->sw_reset) {
3364aefe1c2SAndrea Merello 		ret = regmap_write(priv->regmap, BNO055_SYS_TRIGGER_REG,
3374aefe1c2SAndrea Merello 				   BNO055_SYS_TRIGGER_RST_SYS);
3384aefe1c2SAndrea Merello 		if (ret)
3394aefe1c2SAndrea Merello 			return ret;
3404aefe1c2SAndrea Merello 	} else {
3414aefe1c2SAndrea Merello 		return 0;
3424aefe1c2SAndrea Merello 	}
3434aefe1c2SAndrea Merello 
3444aefe1c2SAndrea Merello 	regcache_drop_region(priv->regmap, 0x0, 0xff);
3454aefe1c2SAndrea Merello 	usleep_range(650000, 700000);
3464aefe1c2SAndrea Merello 
3474aefe1c2SAndrea Merello 	return 0;
3484aefe1c2SAndrea Merello }
3494aefe1c2SAndrea Merello 
bno055_init(struct bno055_priv * priv,const u8 * caldata,int len)3504aefe1c2SAndrea Merello static int bno055_init(struct bno055_priv *priv, const u8 *caldata, int len)
3514aefe1c2SAndrea Merello {
3524aefe1c2SAndrea Merello 	int ret;
3534aefe1c2SAndrea Merello 
3544aefe1c2SAndrea Merello 	ret = bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG);
3554aefe1c2SAndrea Merello 	if (ret)
3564aefe1c2SAndrea Merello 		return ret;
3574aefe1c2SAndrea Merello 
3584aefe1c2SAndrea Merello 	ret = regmap_write(priv->regmap, BNO055_POWER_MODE_REG,
3594aefe1c2SAndrea Merello 			   BNO055_POWER_MODE_NORMAL);
3604aefe1c2SAndrea Merello 	if (ret)
3614aefe1c2SAndrea Merello 		return ret;
3624aefe1c2SAndrea Merello 
3634aefe1c2SAndrea Merello 	ret = regmap_write(priv->regmap, BNO055_SYS_TRIGGER_REG,
3644aefe1c2SAndrea Merello 			   priv->clk ? BNO055_SYS_TRIGGER_CLK_SEL : 0);
3654aefe1c2SAndrea Merello 	if (ret)
3664aefe1c2SAndrea Merello 		return ret;
3674aefe1c2SAndrea Merello 
3684aefe1c2SAndrea Merello 	/* use standard SI units */
3694aefe1c2SAndrea Merello 	ret = regmap_write(priv->regmap, BNO055_UNIT_SEL_REG,
3704aefe1c2SAndrea Merello 			   BNO055_UNIT_SEL_ANDROID | BNO055_UNIT_SEL_GYR_RPS);
3714aefe1c2SAndrea Merello 	if (ret)
3724aefe1c2SAndrea Merello 		return ret;
3734aefe1c2SAndrea Merello 
3744aefe1c2SAndrea Merello 	if (caldata) {
3754aefe1c2SAndrea Merello 		ret = bno055_calibration_load(priv, caldata, len);
3764aefe1c2SAndrea Merello 		if (ret)
3774aefe1c2SAndrea Merello 			dev_warn(priv->dev, "failed to load calibration data with error %d\n",
3784aefe1c2SAndrea Merello 				 ret);
3794aefe1c2SAndrea Merello 	}
3804aefe1c2SAndrea Merello 
3814aefe1c2SAndrea Merello 	return 0;
3824aefe1c2SAndrea Merello }
3834aefe1c2SAndrea Merello 
bno055_operation_mode_set(struct bno055_priv * priv,int operation_mode)3844aefe1c2SAndrea Merello static ssize_t bno055_operation_mode_set(struct bno055_priv *priv,
3854aefe1c2SAndrea Merello 					 int operation_mode)
3864aefe1c2SAndrea Merello {
3874aefe1c2SAndrea Merello 	u8 caldata[BNO055_CALDATA_LEN];
3884aefe1c2SAndrea Merello 	int ret;
3894aefe1c2SAndrea Merello 
3904aefe1c2SAndrea Merello 	mutex_lock(&priv->lock);
3914aefe1c2SAndrea Merello 
3924aefe1c2SAndrea Merello 	ret = bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG);
3934aefe1c2SAndrea Merello 	if (ret)
3944aefe1c2SAndrea Merello 		goto exit_unlock;
3954aefe1c2SAndrea Merello 
3964aefe1c2SAndrea Merello 	if (operation_mode == BNO055_OPR_MODE_FUSION ||
3974aefe1c2SAndrea Merello 	    operation_mode == BNO055_OPR_MODE_FUSION_FMC_OFF) {
3984aefe1c2SAndrea Merello 		/* for entering fusion mode, reset the chip to clear the algo state */
3994aefe1c2SAndrea Merello 		ret = regmap_bulk_read(priv->regmap, BNO055_CALDATA_START, caldata,
4004aefe1c2SAndrea Merello 				       BNO055_CALDATA_LEN);
4014aefe1c2SAndrea Merello 		if (ret)
4024aefe1c2SAndrea Merello 			goto exit_unlock;
4034aefe1c2SAndrea Merello 
4044aefe1c2SAndrea Merello 		ret = bno055_system_reset(priv);
4054aefe1c2SAndrea Merello 		if (ret)
4064aefe1c2SAndrea Merello 			goto exit_unlock;
4074aefe1c2SAndrea Merello 
4084aefe1c2SAndrea Merello 		ret = bno055_init(priv, caldata, BNO055_CALDATA_LEN);
4094aefe1c2SAndrea Merello 		if (ret)
4104aefe1c2SAndrea Merello 			goto exit_unlock;
4114aefe1c2SAndrea Merello 	}
4124aefe1c2SAndrea Merello 
4134aefe1c2SAndrea Merello 	ret = bno055_operation_mode_do_set(priv, operation_mode);
4144aefe1c2SAndrea Merello 	if (ret)
4154aefe1c2SAndrea Merello 		goto exit_unlock;
4164aefe1c2SAndrea Merello 
4174aefe1c2SAndrea Merello 	priv->operation_mode = operation_mode;
4184aefe1c2SAndrea Merello 
4194aefe1c2SAndrea Merello exit_unlock:
4204aefe1c2SAndrea Merello 	mutex_unlock(&priv->lock);
4214aefe1c2SAndrea Merello 	return ret;
4224aefe1c2SAndrea Merello }
4234aefe1c2SAndrea Merello 
bno055_uninit(void * arg)4244aefe1c2SAndrea Merello static void bno055_uninit(void *arg)
4254aefe1c2SAndrea Merello {
4264aefe1c2SAndrea Merello 	struct bno055_priv *priv = arg;
4274aefe1c2SAndrea Merello 
4284aefe1c2SAndrea Merello 	/* stop the IMU */
4294aefe1c2SAndrea Merello 	bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG);
4304aefe1c2SAndrea Merello }
4314aefe1c2SAndrea Merello 
4324aefe1c2SAndrea Merello #define BNO055_CHANNEL(_type, _axis, _index, _address, _sep, _sh, _avail) {	\
4334aefe1c2SAndrea Merello 	.address = _address,							\
4344aefe1c2SAndrea Merello 	.type = _type,								\
4354aefe1c2SAndrea Merello 	.modified = 1,								\
4364aefe1c2SAndrea Merello 	.channel2 = IIO_MOD_##_axis,						\
4374aefe1c2SAndrea Merello 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | (_sep),			\
4384aefe1c2SAndrea Merello 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | (_sh),		\
4394aefe1c2SAndrea Merello 	.info_mask_shared_by_type_available = _avail,				\
4404aefe1c2SAndrea Merello 	.scan_index = _index,							\
4414aefe1c2SAndrea Merello 	.scan_type = {								\
4424aefe1c2SAndrea Merello 		.sign = 's',							\
4434aefe1c2SAndrea Merello 		.realbits = 16,							\
4444aefe1c2SAndrea Merello 		.storagebits = 16,						\
4454aefe1c2SAndrea Merello 		.endianness = IIO_LE,						\
4464aefe1c2SAndrea Merello 		.repeat = IIO_MOD_##_axis == IIO_MOD_QUATERNION ? 4 : 0,        \
4474aefe1c2SAndrea Merello 	},									\
4484aefe1c2SAndrea Merello }
4494aefe1c2SAndrea Merello 
4504aefe1c2SAndrea Merello /* scan indexes follow DATA register order */
4514aefe1c2SAndrea Merello enum bno055_scan_axis {
4524aefe1c2SAndrea Merello 	BNO055_SCAN_ACCEL_X,
4534aefe1c2SAndrea Merello 	BNO055_SCAN_ACCEL_Y,
4544aefe1c2SAndrea Merello 	BNO055_SCAN_ACCEL_Z,
4554aefe1c2SAndrea Merello 	BNO055_SCAN_MAGN_X,
4564aefe1c2SAndrea Merello 	BNO055_SCAN_MAGN_Y,
4574aefe1c2SAndrea Merello 	BNO055_SCAN_MAGN_Z,
4584aefe1c2SAndrea Merello 	BNO055_SCAN_GYRO_X,
4594aefe1c2SAndrea Merello 	BNO055_SCAN_GYRO_Y,
4604aefe1c2SAndrea Merello 	BNO055_SCAN_GYRO_Z,
4614aefe1c2SAndrea Merello 	BNO055_SCAN_YAW,
4624aefe1c2SAndrea Merello 	BNO055_SCAN_ROLL,
4634aefe1c2SAndrea Merello 	BNO055_SCAN_PITCH,
4644aefe1c2SAndrea Merello 	BNO055_SCAN_QUATERNION,
4654aefe1c2SAndrea Merello 	BNO055_SCAN_LIA_X,
4664aefe1c2SAndrea Merello 	BNO055_SCAN_LIA_Y,
4674aefe1c2SAndrea Merello 	BNO055_SCAN_LIA_Z,
4684aefe1c2SAndrea Merello 	BNO055_SCAN_GRAVITY_X,
4694aefe1c2SAndrea Merello 	BNO055_SCAN_GRAVITY_Y,
4704aefe1c2SAndrea Merello 	BNO055_SCAN_GRAVITY_Z,
4714aefe1c2SAndrea Merello 	BNO055_SCAN_TIMESTAMP,
4724aefe1c2SAndrea Merello 	_BNO055_SCAN_MAX
4734aefe1c2SAndrea Merello };
4744aefe1c2SAndrea Merello 
4754aefe1c2SAndrea Merello static const struct iio_chan_spec bno055_channels[] = {
4764aefe1c2SAndrea Merello 	/* accelerometer */
4774aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ACCEL, X, BNO055_SCAN_ACCEL_X,
4784aefe1c2SAndrea Merello 		       BNO055_ACC_DATA_X_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET),
4794aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
4804aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)),
4814aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ACCEL, Y, BNO055_SCAN_ACCEL_Y,
4824aefe1c2SAndrea Merello 		       BNO055_ACC_DATA_Y_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET),
4834aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
4844aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)),
4854aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ACCEL, Z, BNO055_SCAN_ACCEL_Z,
4864aefe1c2SAndrea Merello 		       BNO055_ACC_DATA_Z_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET),
4874aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
4884aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)),
4894aefe1c2SAndrea Merello 	/* gyroscope */
4904aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ANGL_VEL, X, BNO055_SCAN_GYRO_X,
4914aefe1c2SAndrea Merello 		       BNO055_GYR_DATA_X_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET),
4924aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
4934aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
4944aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_SCALE)),
4954aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ANGL_VEL, Y, BNO055_SCAN_GYRO_Y,
4964aefe1c2SAndrea Merello 		       BNO055_GYR_DATA_Y_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET),
4974aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
4984aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
4994aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_SCALE)),
5004aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ANGL_VEL, Z, BNO055_SCAN_GYRO_Z,
5014aefe1c2SAndrea Merello 		       BNO055_GYR_DATA_Z_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET),
5024aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
5034aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
5044aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_SCALE)),
5054aefe1c2SAndrea Merello 	/* magnetometer */
5064aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_MAGN, X, BNO055_SCAN_MAGN_X,
5074aefe1c2SAndrea Merello 		       BNO055_MAG_DATA_X_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET),
5084aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_SAMP_FREQ), BIT(IIO_CHAN_INFO_SAMP_FREQ)),
5094aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_MAGN, Y, BNO055_SCAN_MAGN_Y,
5104aefe1c2SAndrea Merello 		       BNO055_MAG_DATA_Y_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET),
5114aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_SAMP_FREQ), BIT(IIO_CHAN_INFO_SAMP_FREQ)),
5124aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_MAGN, Z, BNO055_SCAN_MAGN_Z,
5134aefe1c2SAndrea Merello 		       BNO055_MAG_DATA_Z_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET),
5144aefe1c2SAndrea Merello 		       BIT(IIO_CHAN_INFO_SAMP_FREQ), BIT(IIO_CHAN_INFO_SAMP_FREQ)),
5154aefe1c2SAndrea Merello 	/* euler angle */
5164aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ROT, YAW, BNO055_SCAN_YAW,
5174aefe1c2SAndrea Merello 		       BNO055_EUL_DATA_X_LSB_REG, 0, 0, 0),
5184aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ROT, ROLL, BNO055_SCAN_ROLL,
5194aefe1c2SAndrea Merello 		       BNO055_EUL_DATA_Y_LSB_REG, 0, 0, 0),
5204aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ROT, PITCH, BNO055_SCAN_PITCH,
5214aefe1c2SAndrea Merello 		       BNO055_EUL_DATA_Z_LSB_REG, 0, 0, 0),
5224aefe1c2SAndrea Merello 	/* quaternion */
5234aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ROT, QUATERNION, BNO055_SCAN_QUATERNION,
5244aefe1c2SAndrea Merello 		       BNO055_QUAT_DATA_W_LSB_REG, 0, 0, 0),
5254aefe1c2SAndrea Merello 
5264aefe1c2SAndrea Merello 	/* linear acceleration */
5274aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ACCEL, LINEAR_X, BNO055_SCAN_LIA_X,
5284aefe1c2SAndrea Merello 		       BNO055_LIA_DATA_X_LSB_REG, 0, 0, 0),
5294aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ACCEL, LINEAR_Y, BNO055_SCAN_LIA_Y,
5304aefe1c2SAndrea Merello 		       BNO055_LIA_DATA_Y_LSB_REG, 0, 0, 0),
5314aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_ACCEL, LINEAR_Z, BNO055_SCAN_LIA_Z,
5324aefe1c2SAndrea Merello 		       BNO055_LIA_DATA_Z_LSB_REG, 0, 0, 0),
5334aefe1c2SAndrea Merello 
5344aefe1c2SAndrea Merello 	/* gravity vector */
5354aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_GRAVITY, X, BNO055_SCAN_GRAVITY_X,
5364aefe1c2SAndrea Merello 		       BNO055_GRAVITY_DATA_X_LSB_REG, 0, 0, 0),
5374aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_GRAVITY, Y, BNO055_SCAN_GRAVITY_Y,
5384aefe1c2SAndrea Merello 		       BNO055_GRAVITY_DATA_Y_LSB_REG, 0, 0, 0),
5394aefe1c2SAndrea Merello 	BNO055_CHANNEL(IIO_GRAVITY, Z, BNO055_SCAN_GRAVITY_Z,
5404aefe1c2SAndrea Merello 		       BNO055_GRAVITY_DATA_Z_LSB_REG, 0, 0, 0),
5414aefe1c2SAndrea Merello 
5424aefe1c2SAndrea Merello 	{
5434aefe1c2SAndrea Merello 		.type = IIO_TEMP,
5444aefe1c2SAndrea Merello 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
5454aefe1c2SAndrea Merello 		.scan_index = -1,
5464aefe1c2SAndrea Merello 	},
5474aefe1c2SAndrea Merello 	IIO_CHAN_SOFT_TIMESTAMP(BNO055_SCAN_TIMESTAMP),
5484aefe1c2SAndrea Merello };
5494aefe1c2SAndrea Merello 
bno055_get_regmask(struct bno055_priv * priv,int * val,int * val2,int reg,int mask,struct bno055_sysfs_attr * attr)5504aefe1c2SAndrea Merello static int bno055_get_regmask(struct bno055_priv *priv, int *val, int *val2,
5514aefe1c2SAndrea Merello 			      int reg, int mask, struct bno055_sysfs_attr *attr)
5524aefe1c2SAndrea Merello {
5534aefe1c2SAndrea Merello 	const int shift = __ffs(mask);
5544aefe1c2SAndrea Merello 	int hwval, idx;
5554aefe1c2SAndrea Merello 	int ret;
5564aefe1c2SAndrea Merello 	int i;
5574aefe1c2SAndrea Merello 
5584aefe1c2SAndrea Merello 	ret = regmap_read(priv->regmap, reg, &hwval);
5594aefe1c2SAndrea Merello 	if (ret)
5604aefe1c2SAndrea Merello 		return ret;
5614aefe1c2SAndrea Merello 
5624aefe1c2SAndrea Merello 	idx = (hwval & mask) >> shift;
5634aefe1c2SAndrea Merello 	if (attr->hw_xlate)
5644aefe1c2SAndrea Merello 		for (i = 0; i < attr->len; i++)
5654aefe1c2SAndrea Merello 			if (attr->hw_xlate[i] == idx) {
5664aefe1c2SAndrea Merello 				idx = i;
5674aefe1c2SAndrea Merello 				break;
5684aefe1c2SAndrea Merello 			}
5694aefe1c2SAndrea Merello 	if (attr->type == IIO_VAL_INT) {
5704aefe1c2SAndrea Merello 		*val = attr->vals[idx];
5714aefe1c2SAndrea Merello 	} else { /* IIO_VAL_INT_PLUS_MICRO or IIO_VAL_FRACTIONAL */
5724aefe1c2SAndrea Merello 		*val = attr->vals[idx * 2];
5734aefe1c2SAndrea Merello 		*val2 = attr->vals[idx * 2 + 1];
5744aefe1c2SAndrea Merello 	}
5754aefe1c2SAndrea Merello 
5764aefe1c2SAndrea Merello 	return attr->type;
5774aefe1c2SAndrea Merello }
5784aefe1c2SAndrea Merello 
bno055_set_regmask(struct bno055_priv * priv,int val,int val2,int reg,int mask,struct bno055_sysfs_attr * attr)5794aefe1c2SAndrea Merello static int bno055_set_regmask(struct bno055_priv *priv, int val, int val2,
5804aefe1c2SAndrea Merello 			      int reg, int mask, struct bno055_sysfs_attr *attr)
5814aefe1c2SAndrea Merello {
5824aefe1c2SAndrea Merello 	const int shift = __ffs(mask);
5834aefe1c2SAndrea Merello 	int best_delta;
5844aefe1c2SAndrea Merello 	int req_val;
5854aefe1c2SAndrea Merello 	int tbl_val;
5864aefe1c2SAndrea Merello 	bool first;
5874aefe1c2SAndrea Merello 	int delta;
5884aefe1c2SAndrea Merello 	int hwval;
5894aefe1c2SAndrea Merello 	int ret;
5904aefe1c2SAndrea Merello 	int len;
5914aefe1c2SAndrea Merello 	int i;
5924aefe1c2SAndrea Merello 
5934aefe1c2SAndrea Merello 	/*
5944aefe1c2SAndrea Merello 	 * The closest value the HW supports is only one in fusion mode,
5954aefe1c2SAndrea Merello 	 * and it is autoselected, so don't do anything, just return OK,
5964aefe1c2SAndrea Merello 	 * as the closest possible value has been (virtually) selected
5974aefe1c2SAndrea Merello 	 */
5984aefe1c2SAndrea Merello 	if (priv->operation_mode != BNO055_OPR_MODE_AMG)
5994aefe1c2SAndrea Merello 		return 0;
6004aefe1c2SAndrea Merello 
6014aefe1c2SAndrea Merello 	len = attr->len;
6024aefe1c2SAndrea Merello 
6034aefe1c2SAndrea Merello 	/*
6044aefe1c2SAndrea Merello 	 * We always get a request in INT_PLUS_MICRO, but we
6054aefe1c2SAndrea Merello 	 * take care of the micro part only when we really have
6064aefe1c2SAndrea Merello 	 * non-integer tables. This prevents 32-bit overflow with
6074aefe1c2SAndrea Merello 	 * larger integers contained in integer tables.
6084aefe1c2SAndrea Merello 	 */
6094aefe1c2SAndrea Merello 	req_val = val;
6104aefe1c2SAndrea Merello 	if (attr->type != IIO_VAL_INT) {
6114aefe1c2SAndrea Merello 		len /= 2;
6124aefe1c2SAndrea Merello 		req_val = min(val, 2147) * 1000000 + val2;
6134aefe1c2SAndrea Merello 	}
6144aefe1c2SAndrea Merello 
6154aefe1c2SAndrea Merello 	first = true;
6164aefe1c2SAndrea Merello 	for (i = 0; i < len; i++) {
6174aefe1c2SAndrea Merello 		switch (attr->type) {
6184aefe1c2SAndrea Merello 		case IIO_VAL_INT:
6194aefe1c2SAndrea Merello 			tbl_val = attr->vals[i];
6204aefe1c2SAndrea Merello 			break;
6214aefe1c2SAndrea Merello 		case IIO_VAL_INT_PLUS_MICRO:
6224aefe1c2SAndrea Merello 			WARN_ON(attr->vals[i * 2] > 2147);
6234aefe1c2SAndrea Merello 			tbl_val = attr->vals[i * 2] * 1000000 +
6244aefe1c2SAndrea Merello 				attr->vals[i * 2 + 1];
6254aefe1c2SAndrea Merello 			break;
6264aefe1c2SAndrea Merello 		case IIO_VAL_FRACTIONAL:
6274aefe1c2SAndrea Merello 			WARN_ON(attr->vals[i * 2] > 4294);
6284aefe1c2SAndrea Merello 			tbl_val = attr->vals[i * 2] * 1000000 /
6294aefe1c2SAndrea Merello 				attr->vals[i * 2 + 1];
6304aefe1c2SAndrea Merello 			break;
6314aefe1c2SAndrea Merello 		default:
6324aefe1c2SAndrea Merello 			return -EINVAL;
6334aefe1c2SAndrea Merello 		}
6344aefe1c2SAndrea Merello 		delta = abs(tbl_val - req_val);
635*dd4753f8SDan Carpenter 		if (first || delta < best_delta) {
6364aefe1c2SAndrea Merello 			best_delta = delta;
6374aefe1c2SAndrea Merello 			hwval = i;
6384aefe1c2SAndrea Merello 			first = false;
6394aefe1c2SAndrea Merello 		}
6404aefe1c2SAndrea Merello 	}
6414aefe1c2SAndrea Merello 
6424aefe1c2SAndrea Merello 	if (attr->hw_xlate)
6434aefe1c2SAndrea Merello 		hwval = attr->hw_xlate[hwval];
6444aefe1c2SAndrea Merello 
6454aefe1c2SAndrea Merello 	ret = bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG);
6464aefe1c2SAndrea Merello 	if (ret)
6474aefe1c2SAndrea Merello 		return ret;
6484aefe1c2SAndrea Merello 
6494aefe1c2SAndrea Merello 	ret = regmap_update_bits(priv->regmap, reg, mask, hwval << shift);
6504aefe1c2SAndrea Merello 	if (ret)
6514aefe1c2SAndrea Merello 		return ret;
6524aefe1c2SAndrea Merello 
6534aefe1c2SAndrea Merello 	return bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_AMG);
6544aefe1c2SAndrea Merello }
6554aefe1c2SAndrea Merello 
bno055_read_simple_chan(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)6564aefe1c2SAndrea Merello static int bno055_read_simple_chan(struct iio_dev *indio_dev,
6574aefe1c2SAndrea Merello 				   struct iio_chan_spec const *chan,
6584aefe1c2SAndrea Merello 				   int *val, int *val2, long mask)
6594aefe1c2SAndrea Merello {
6604aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(indio_dev);
6614aefe1c2SAndrea Merello 	__le16 raw_val;
6624aefe1c2SAndrea Merello 	int ret;
6634aefe1c2SAndrea Merello 
6644aefe1c2SAndrea Merello 	switch (mask) {
6654aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_RAW:
6664aefe1c2SAndrea Merello 		ret = regmap_bulk_read(priv->regmap, chan->address,
6674aefe1c2SAndrea Merello 				       &raw_val, sizeof(raw_val));
6684aefe1c2SAndrea Merello 		if (ret < 0)
6694aefe1c2SAndrea Merello 			return ret;
6704aefe1c2SAndrea Merello 		*val = sign_extend32(le16_to_cpu(raw_val), 15);
6714aefe1c2SAndrea Merello 		return IIO_VAL_INT;
6724aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_OFFSET:
6734aefe1c2SAndrea Merello 		if (priv->operation_mode != BNO055_OPR_MODE_AMG) {
6744aefe1c2SAndrea Merello 			*val = 0;
6754aefe1c2SAndrea Merello 		} else {
6764aefe1c2SAndrea Merello 			ret = regmap_bulk_read(priv->regmap,
6774aefe1c2SAndrea Merello 					       chan->address +
6784aefe1c2SAndrea Merello 					       BNO055_REG_OFFSET_ADDR,
6794aefe1c2SAndrea Merello 					       &raw_val, sizeof(raw_val));
6804aefe1c2SAndrea Merello 			if (ret < 0)
6814aefe1c2SAndrea Merello 				return ret;
6824aefe1c2SAndrea Merello 			/*
6834aefe1c2SAndrea Merello 			 * IMU reports sensor offsets; IIO wants correction
6844aefe1c2SAndrea Merello 			 * offsets, thus we need the 'minus' here.
6854aefe1c2SAndrea Merello 			 */
6864aefe1c2SAndrea Merello 			*val = -sign_extend32(le16_to_cpu(raw_val), 15);
6874aefe1c2SAndrea Merello 		}
6884aefe1c2SAndrea Merello 		return IIO_VAL_INT;
6894aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_SCALE:
6904aefe1c2SAndrea Merello 		*val = 1;
6914aefe1c2SAndrea Merello 		switch (chan->type) {
6924aefe1c2SAndrea Merello 		case IIO_GRAVITY:
6934aefe1c2SAndrea Merello 			/* Table 3-35: 1 m/s^2 = 100 LSB */
6944aefe1c2SAndrea Merello 		case IIO_ACCEL:
6954aefe1c2SAndrea Merello 			/* Table 3-17: 1 m/s^2 = 100 LSB */
6964aefe1c2SAndrea Merello 			*val2 = 100;
6974aefe1c2SAndrea Merello 			break;
6984aefe1c2SAndrea Merello 		case IIO_MAGN:
6994aefe1c2SAndrea Merello 			/*
7004aefe1c2SAndrea Merello 			 * Table 3-19: 1 uT = 16 LSB.  But we need
7014aefe1c2SAndrea Merello 			 * Gauss: 1G = 0.1 uT.
7024aefe1c2SAndrea Merello 			 */
7034aefe1c2SAndrea Merello 			*val2 = 160;
7044aefe1c2SAndrea Merello 			break;
7054aefe1c2SAndrea Merello 		case IIO_ANGL_VEL:
7064aefe1c2SAndrea Merello 			/*
7074aefe1c2SAndrea Merello 			 * Table 3-22: 1 Rps = 900 LSB
7084aefe1c2SAndrea Merello 			 * .. but this is not exactly true. See comment at the
7094aefe1c2SAndrea Merello 			 * beginning of this file.
7104aefe1c2SAndrea Merello 			 */
7114aefe1c2SAndrea Merello 			if (priv->operation_mode != BNO055_OPR_MODE_AMG) {
7124aefe1c2SAndrea Merello 				*val = bno055_gyr_scale.fusion_vals[0];
7134aefe1c2SAndrea Merello 				*val2 = bno055_gyr_scale.fusion_vals[1];
7144aefe1c2SAndrea Merello 				return IIO_VAL_FRACTIONAL;
7154aefe1c2SAndrea Merello 			}
7164aefe1c2SAndrea Merello 
7174aefe1c2SAndrea Merello 			return bno055_get_regmask(priv, val, val2,
7184aefe1c2SAndrea Merello 						  BNO055_GYR_CONFIG_REG,
7194aefe1c2SAndrea Merello 						  BNO055_GYR_CONFIG_RANGE_MASK,
7204aefe1c2SAndrea Merello 						  &bno055_gyr_scale);
7214aefe1c2SAndrea Merello 			break;
7224aefe1c2SAndrea Merello 		case IIO_ROT:
7234aefe1c2SAndrea Merello 			/* Table 3-28: 1 degree = 16 LSB */
7244aefe1c2SAndrea Merello 			*val2 = 16;
7254aefe1c2SAndrea Merello 			break;
7264aefe1c2SAndrea Merello 		default:
7274aefe1c2SAndrea Merello 			return -EINVAL;
7284aefe1c2SAndrea Merello 		}
7294aefe1c2SAndrea Merello 		return IIO_VAL_FRACTIONAL;
7304aefe1c2SAndrea Merello 
7314aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_SAMP_FREQ:
7324aefe1c2SAndrea Merello 		if (chan->type != IIO_MAGN)
7334aefe1c2SAndrea Merello 			return -EINVAL;
7344aefe1c2SAndrea Merello 
7354aefe1c2SAndrea Merello 		return bno055_get_regmask(priv, val, val2,
7364aefe1c2SAndrea Merello 					  BNO055_MAG_CONFIG_REG,
7374aefe1c2SAndrea Merello 					  BNO055_MAG_CONFIG_ODR_MASK,
7384aefe1c2SAndrea Merello 					  &bno055_mag_odr);
7394aefe1c2SAndrea Merello 
7404aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
7414aefe1c2SAndrea Merello 		switch (chan->type) {
7424aefe1c2SAndrea Merello 		case IIO_ANGL_VEL:
7434aefe1c2SAndrea Merello 			return bno055_get_regmask(priv, val, val2,
7444aefe1c2SAndrea Merello 						  BNO055_GYR_CONFIG_REG,
7454aefe1c2SAndrea Merello 						  BNO055_GYR_CONFIG_LPF_MASK,
7464aefe1c2SAndrea Merello 						  &bno055_gyr_lpf);
7474aefe1c2SAndrea Merello 		case IIO_ACCEL:
7484aefe1c2SAndrea Merello 			return bno055_get_regmask(priv, val, val2,
7494aefe1c2SAndrea Merello 						  BNO055_ACC_CONFIG_REG,
7504aefe1c2SAndrea Merello 						  BNO055_ACC_CONFIG_LPF_MASK,
7514aefe1c2SAndrea Merello 						  &bno055_acc_lpf);
7524aefe1c2SAndrea Merello 		default:
7534aefe1c2SAndrea Merello 			return -EINVAL;
7544aefe1c2SAndrea Merello 		}
7554aefe1c2SAndrea Merello 
7564aefe1c2SAndrea Merello 	default:
7574aefe1c2SAndrea Merello 		return -EINVAL;
7584aefe1c2SAndrea Merello 	}
7594aefe1c2SAndrea Merello }
7604aefe1c2SAndrea Merello 
bno055_sysfs_attr_avail(struct bno055_priv * priv,struct bno055_sysfs_attr * attr,const int ** vals,int * length)7614aefe1c2SAndrea Merello static int bno055_sysfs_attr_avail(struct bno055_priv *priv, struct bno055_sysfs_attr *attr,
7624aefe1c2SAndrea Merello 				   const int **vals, int *length)
7634aefe1c2SAndrea Merello {
7644aefe1c2SAndrea Merello 	if (priv->operation_mode != BNO055_OPR_MODE_AMG) {
7654aefe1c2SAndrea Merello 		/* locked when fusion enabled */
7664aefe1c2SAndrea Merello 		*vals = attr->fusion_vals;
7674aefe1c2SAndrea Merello 		if (attr->type == IIO_VAL_INT)
7684aefe1c2SAndrea Merello 			*length = 1;
7694aefe1c2SAndrea Merello 		else
7704aefe1c2SAndrea Merello 			*length = 2; /* IIO_VAL_INT_PLUS_MICRO or IIO_VAL_FRACTIONAL*/
7714aefe1c2SAndrea Merello 	} else {
7724aefe1c2SAndrea Merello 		*vals = attr->vals;
7734aefe1c2SAndrea Merello 		*length = attr->len;
7744aefe1c2SAndrea Merello 	}
7754aefe1c2SAndrea Merello 
7764aefe1c2SAndrea Merello 	return attr->type;
7774aefe1c2SAndrea Merello }
7784aefe1c2SAndrea Merello 
bno055_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)7794aefe1c2SAndrea Merello static int bno055_read_avail(struct iio_dev *indio_dev,
7804aefe1c2SAndrea Merello 			     struct iio_chan_spec const *chan,
7814aefe1c2SAndrea Merello 			     const int **vals, int *type, int *length,
7824aefe1c2SAndrea Merello 			     long mask)
7834aefe1c2SAndrea Merello {
7844aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(indio_dev);
7854aefe1c2SAndrea Merello 
7864aefe1c2SAndrea Merello 	switch (mask) {
7874aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_SCALE:
7884aefe1c2SAndrea Merello 		switch (chan->type) {
7894aefe1c2SAndrea Merello 		case IIO_ANGL_VEL:
7904aefe1c2SAndrea Merello 			*type = bno055_sysfs_attr_avail(priv, &bno055_gyr_scale,
7914aefe1c2SAndrea Merello 							vals, length);
7924aefe1c2SAndrea Merello 			return IIO_AVAIL_LIST;
7934aefe1c2SAndrea Merello 		default:
7944aefe1c2SAndrea Merello 			return -EINVAL;
7954aefe1c2SAndrea Merello 		}
7964aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
7974aefe1c2SAndrea Merello 		switch (chan->type) {
7984aefe1c2SAndrea Merello 		case IIO_ANGL_VEL:
7994aefe1c2SAndrea Merello 			*type = bno055_sysfs_attr_avail(priv, &bno055_gyr_lpf,
8004aefe1c2SAndrea Merello 							vals, length);
8014aefe1c2SAndrea Merello 			return IIO_AVAIL_LIST;
8024aefe1c2SAndrea Merello 		case IIO_ACCEL:
8034aefe1c2SAndrea Merello 			*type = bno055_sysfs_attr_avail(priv, &bno055_acc_lpf,
8044aefe1c2SAndrea Merello 							vals, length);
8054aefe1c2SAndrea Merello 			return IIO_AVAIL_LIST;
8064aefe1c2SAndrea Merello 		default:
8074aefe1c2SAndrea Merello 			return -EINVAL;
8084aefe1c2SAndrea Merello 		}
8094aefe1c2SAndrea Merello 
8104aefe1c2SAndrea Merello 		break;
8114aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_SAMP_FREQ:
8124aefe1c2SAndrea Merello 		switch (chan->type) {
8134aefe1c2SAndrea Merello 		case IIO_MAGN:
8144aefe1c2SAndrea Merello 			*type = bno055_sysfs_attr_avail(priv, &bno055_mag_odr,
8154aefe1c2SAndrea Merello 							vals, length);
8164aefe1c2SAndrea Merello 			return IIO_AVAIL_LIST;
8174aefe1c2SAndrea Merello 		default:
8184aefe1c2SAndrea Merello 			return -EINVAL;
8194aefe1c2SAndrea Merello 		}
8204aefe1c2SAndrea Merello 	default:
8214aefe1c2SAndrea Merello 		return -EINVAL;
8224aefe1c2SAndrea Merello 	}
8234aefe1c2SAndrea Merello }
8244aefe1c2SAndrea Merello 
bno055_read_temp_chan(struct iio_dev * indio_dev,int * val)8254aefe1c2SAndrea Merello static int bno055_read_temp_chan(struct iio_dev *indio_dev, int *val)
8264aefe1c2SAndrea Merello {
8274aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(indio_dev);
8284aefe1c2SAndrea Merello 	unsigned int raw_val;
8294aefe1c2SAndrea Merello 	int ret;
8304aefe1c2SAndrea Merello 
8314aefe1c2SAndrea Merello 	ret = regmap_read(priv->regmap, BNO055_TEMP_REG, &raw_val);
8324aefe1c2SAndrea Merello 	if (ret < 0)
8334aefe1c2SAndrea Merello 		return ret;
8344aefe1c2SAndrea Merello 
8354aefe1c2SAndrea Merello 	/*
8364aefe1c2SAndrea Merello 	 * Tables 3-36 and 3-37: one byte of priv, signed, 1 LSB = 1C.
8374aefe1c2SAndrea Merello 	 * ABI wants milliC.
8384aefe1c2SAndrea Merello 	 */
8394aefe1c2SAndrea Merello 	*val = raw_val * 1000;
8404aefe1c2SAndrea Merello 
8414aefe1c2SAndrea Merello 	return IIO_VAL_INT;
8424aefe1c2SAndrea Merello }
8434aefe1c2SAndrea Merello 
bno055_read_quaternion(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int size,int * vals,int * val_len,long mask)8444aefe1c2SAndrea Merello static int bno055_read_quaternion(struct iio_dev *indio_dev,
8454aefe1c2SAndrea Merello 				  struct iio_chan_spec const *chan,
8464aefe1c2SAndrea Merello 				  int size, int *vals, int *val_len,
8474aefe1c2SAndrea Merello 				  long mask)
8484aefe1c2SAndrea Merello {
8494aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(indio_dev);
8504aefe1c2SAndrea Merello 	__le16 raw_vals[4];
8514aefe1c2SAndrea Merello 	int i, ret;
8524aefe1c2SAndrea Merello 
8534aefe1c2SAndrea Merello 	switch (mask) {
8544aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_RAW:
8554aefe1c2SAndrea Merello 		if (size < 4)
8564aefe1c2SAndrea Merello 			return -EINVAL;
8574aefe1c2SAndrea Merello 		ret = regmap_bulk_read(priv->regmap,
8584aefe1c2SAndrea Merello 				       BNO055_QUAT_DATA_W_LSB_REG,
8594aefe1c2SAndrea Merello 				       raw_vals, sizeof(raw_vals));
8604aefe1c2SAndrea Merello 		if (ret < 0)
8614aefe1c2SAndrea Merello 			return ret;
8624aefe1c2SAndrea Merello 		for (i = 0; i < 4; i++)
8634aefe1c2SAndrea Merello 			vals[i] = sign_extend32(le16_to_cpu(raw_vals[i]), 15);
8644aefe1c2SAndrea Merello 		*val_len = 4;
8654aefe1c2SAndrea Merello 		return IIO_VAL_INT_MULTIPLE;
8664aefe1c2SAndrea Merello 	case IIO_CHAN_INFO_SCALE:
8674aefe1c2SAndrea Merello 		/* Table 3-31: 1 quaternion = 2^14 LSB */
8684aefe1c2SAndrea Merello 		if (size < 2)
8694aefe1c2SAndrea Merello 			return -EINVAL;
8704aefe1c2SAndrea Merello 		vals[0] = 1;
8714aefe1c2SAndrea Merello 		vals[1] = 14;
8724aefe1c2SAndrea Merello 		return IIO_VAL_FRACTIONAL_LOG2;
8734aefe1c2SAndrea Merello 	default:
8744aefe1c2SAndrea Merello 		return -EINVAL;
8754aefe1c2SAndrea Merello 	}
8764aefe1c2SAndrea Merello }
8774aefe1c2SAndrea Merello 
bno055_is_chan_readable(struct iio_dev * indio_dev,struct iio_chan_spec const * chan)8784aefe1c2SAndrea Merello static bool bno055_is_chan_readable(struct iio_dev *indio_dev,
8794aefe1c2SAndrea Merello 				    struct iio_chan_spec const *chan)
8804aefe1c2SAndrea Merello {
8814aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(indio_dev);
8824aefe1c2SAndrea Merello 
8834aefe1c2SAndrea Merello 	if (priv->operation_mode != BNO055_OPR_MODE_AMG)
8844aefe1c2SAndrea Merello 		return true;
8854aefe1c2SAndrea Merello 
8864aefe1c2SAndrea Merello 	switch (chan->type) {
8874aefe1c2SAndrea Merello 	case IIO_GRAVITY:
8884aefe1c2SAndrea Merello 	case IIO_ROT:
8894aefe1c2SAndrea Merello 		return false;
8904aefe1c2SAndrea Merello 	case IIO_ACCEL:
8914aefe1c2SAndrea Merello 		if (chan->channel2 == IIO_MOD_LINEAR_X ||
8924aefe1c2SAndrea Merello 		    chan->channel2 == IIO_MOD_LINEAR_Y ||
8934aefe1c2SAndrea Merello 		    chan->channel2 == IIO_MOD_LINEAR_Z)
8944aefe1c2SAndrea Merello 			return false;
8954aefe1c2SAndrea Merello 		return true;
8964aefe1c2SAndrea Merello 	default:
8974aefe1c2SAndrea Merello 		return true;
8984aefe1c2SAndrea Merello 	}
8994aefe1c2SAndrea Merello }
9004aefe1c2SAndrea Merello 
_bno055_read_raw_multi(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int size,int * vals,int * val_len,long mask)9014aefe1c2SAndrea Merello static int _bno055_read_raw_multi(struct iio_dev *indio_dev,
9024aefe1c2SAndrea Merello 				  struct iio_chan_spec const *chan,
9034aefe1c2SAndrea Merello 				  int size, int *vals, int *val_len,
9044aefe1c2SAndrea Merello 				  long mask)
9054aefe1c2SAndrea Merello {
9064aefe1c2SAndrea Merello 	if (!bno055_is_chan_readable(indio_dev, chan))
9074aefe1c2SAndrea Merello 		return -EBUSY;
9084aefe1c2SAndrea Merello 
9094aefe1c2SAndrea Merello 	switch (chan->type) {
9104aefe1c2SAndrea Merello 	case IIO_MAGN:
9114aefe1c2SAndrea Merello 	case IIO_ACCEL:
9124aefe1c2SAndrea Merello 	case IIO_ANGL_VEL:
9134aefe1c2SAndrea Merello 	case IIO_GRAVITY:
9144aefe1c2SAndrea Merello 		if (size < 2)
9154aefe1c2SAndrea Merello 			return -EINVAL;
9164aefe1c2SAndrea Merello 		*val_len = 2;
9174aefe1c2SAndrea Merello 		return bno055_read_simple_chan(indio_dev, chan,
9184aefe1c2SAndrea Merello 					       &vals[0], &vals[1],
9194aefe1c2SAndrea Merello 					       mask);
9204aefe1c2SAndrea Merello 	case IIO_TEMP:
9214aefe1c2SAndrea Merello 		*val_len = 1;
9224aefe1c2SAndrea Merello 		return bno055_read_temp_chan(indio_dev, &vals[0]);
9234aefe1c2SAndrea Merello 	case IIO_ROT:
9244aefe1c2SAndrea Merello 		/*
9254aefe1c2SAndrea Merello 		 * Rotation is exposed as either a quaternion or three
9264aefe1c2SAndrea Merello 		 * Euler angles.
9274aefe1c2SAndrea Merello 		 */
9284aefe1c2SAndrea Merello 		if (chan->channel2 == IIO_MOD_QUATERNION)
9294aefe1c2SAndrea Merello 			return bno055_read_quaternion(indio_dev, chan,
9304aefe1c2SAndrea Merello 						      size, vals,
9314aefe1c2SAndrea Merello 						      val_len, mask);
9324aefe1c2SAndrea Merello 		if (size < 2)
9334aefe1c2SAndrea Merello 			return -EINVAL;
9344aefe1c2SAndrea Merello 		*val_len = 2;
9354aefe1c2SAndrea Merello 		return bno055_read_simple_chan(indio_dev, chan,
9364aefe1c2SAndrea Merello 					       &vals[0], &vals[1],
9374aefe1c2SAndrea Merello 					       mask);
9384aefe1c2SAndrea Merello 	default:
9394aefe1c2SAndrea Merello 		return -EINVAL;
9404aefe1c2SAndrea Merello 	}
9414aefe1c2SAndrea Merello }
9424aefe1c2SAndrea Merello 
bno055_read_raw_multi(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int size,int * vals,int * val_len,long mask)9434aefe1c2SAndrea Merello static int bno055_read_raw_multi(struct iio_dev *indio_dev,
9444aefe1c2SAndrea Merello 				 struct iio_chan_spec const *chan,
9454aefe1c2SAndrea Merello 				 int size, int *vals, int *val_len,
9464aefe1c2SAndrea Merello 				 long mask)
9474aefe1c2SAndrea Merello {
9484aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(indio_dev);
9494aefe1c2SAndrea Merello 	int ret;
9504aefe1c2SAndrea Merello 
9514aefe1c2SAndrea Merello 	mutex_lock(&priv->lock);
9524aefe1c2SAndrea Merello 	ret = _bno055_read_raw_multi(indio_dev, chan, size,
9534aefe1c2SAndrea Merello 				     vals, val_len, mask);
9544aefe1c2SAndrea Merello 	mutex_unlock(&priv->lock);
9554aefe1c2SAndrea Merello 	return ret;
9564aefe1c2SAndrea Merello }
9574aefe1c2SAndrea Merello 
_bno055_write_raw(struct iio_dev * iio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)9584aefe1c2SAndrea Merello static int _bno055_write_raw(struct iio_dev *iio_dev,
9594aefe1c2SAndrea Merello 			     struct iio_chan_spec const *chan,
9604aefe1c2SAndrea Merello 			     int val, int val2, long mask)
9614aefe1c2SAndrea Merello {
9624aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(iio_dev);
9634aefe1c2SAndrea Merello 
9644aefe1c2SAndrea Merello 	switch (chan->type) {
9654aefe1c2SAndrea Merello 	case IIO_MAGN:
9664aefe1c2SAndrea Merello 		switch (mask) {
9674aefe1c2SAndrea Merello 		case IIO_CHAN_INFO_SAMP_FREQ:
9684aefe1c2SAndrea Merello 			return bno055_set_regmask(priv, val, val2,
9694aefe1c2SAndrea Merello 						  BNO055_MAG_CONFIG_REG,
9704aefe1c2SAndrea Merello 						  BNO055_MAG_CONFIG_ODR_MASK,
9714aefe1c2SAndrea Merello 						  &bno055_mag_odr);
9724aefe1c2SAndrea Merello 		default:
9734aefe1c2SAndrea Merello 			return -EINVAL;
9744aefe1c2SAndrea Merello 		}
9754aefe1c2SAndrea Merello 	case IIO_ACCEL:
9764aefe1c2SAndrea Merello 		switch (mask) {
9774aefe1c2SAndrea Merello 		case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
9784aefe1c2SAndrea Merello 			return bno055_set_regmask(priv, val, val2,
9794aefe1c2SAndrea Merello 						  BNO055_ACC_CONFIG_REG,
9804aefe1c2SAndrea Merello 						  BNO055_ACC_CONFIG_LPF_MASK,
9814aefe1c2SAndrea Merello 						  &bno055_acc_lpf);
9824aefe1c2SAndrea Merello 
9834aefe1c2SAndrea Merello 		default:
9844aefe1c2SAndrea Merello 			return -EINVAL;
9854aefe1c2SAndrea Merello 		}
9864aefe1c2SAndrea Merello 	case IIO_ANGL_VEL:
9874aefe1c2SAndrea Merello 		switch (mask) {
9884aefe1c2SAndrea Merello 		case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
9894aefe1c2SAndrea Merello 			return bno055_set_regmask(priv, val, val2,
9904aefe1c2SAndrea Merello 						  BNO055_GYR_CONFIG_REG,
9914aefe1c2SAndrea Merello 						  BNO055_GYR_CONFIG_LPF_MASK,
9924aefe1c2SAndrea Merello 						  &bno055_gyr_lpf);
9934aefe1c2SAndrea Merello 		case IIO_CHAN_INFO_SCALE:
9944aefe1c2SAndrea Merello 			return bno055_set_regmask(priv, val, val2,
9954aefe1c2SAndrea Merello 						  BNO055_GYR_CONFIG_REG,
9964aefe1c2SAndrea Merello 						  BNO055_GYR_CONFIG_RANGE_MASK,
9974aefe1c2SAndrea Merello 						  &bno055_gyr_scale);
9984aefe1c2SAndrea Merello 		default:
9994aefe1c2SAndrea Merello 			return -EINVAL;
10004aefe1c2SAndrea Merello 		}
10014aefe1c2SAndrea Merello 	default:
10024aefe1c2SAndrea Merello 		return -EINVAL;
10034aefe1c2SAndrea Merello 	}
10044aefe1c2SAndrea Merello }
10054aefe1c2SAndrea Merello 
bno055_write_raw(struct iio_dev * iio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)10064aefe1c2SAndrea Merello static int bno055_write_raw(struct iio_dev *iio_dev,
10074aefe1c2SAndrea Merello 			    struct iio_chan_spec const *chan,
10084aefe1c2SAndrea Merello 			    int val, int val2, long mask)
10094aefe1c2SAndrea Merello {
10104aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(iio_dev);
10114aefe1c2SAndrea Merello 	int ret;
10124aefe1c2SAndrea Merello 
10134aefe1c2SAndrea Merello 	mutex_lock(&priv->lock);
10144aefe1c2SAndrea Merello 	ret = _bno055_write_raw(iio_dev, chan, val, val2, mask);
10154aefe1c2SAndrea Merello 	mutex_unlock(&priv->lock);
10164aefe1c2SAndrea Merello 
10174aefe1c2SAndrea Merello 	return ret;
10184aefe1c2SAndrea Merello }
10194aefe1c2SAndrea Merello 
in_accel_range_raw_available_show(struct device * dev,struct device_attribute * attr,char * buf)10204aefe1c2SAndrea Merello static ssize_t in_accel_range_raw_available_show(struct device *dev,
10214aefe1c2SAndrea Merello 						 struct device_attribute *attr,
10224aefe1c2SAndrea Merello 						 char *buf)
10234aefe1c2SAndrea Merello {
10244aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev));
10254aefe1c2SAndrea Merello 	int len = 0;
10264aefe1c2SAndrea Merello 	int i;
10274aefe1c2SAndrea Merello 
10284aefe1c2SAndrea Merello 	if (priv->operation_mode != BNO055_OPR_MODE_AMG)
10294aefe1c2SAndrea Merello 		return sysfs_emit(buf, "%d\n", bno055_acc_range.fusion_vals[0]);
10304aefe1c2SAndrea Merello 
10314aefe1c2SAndrea Merello 	for (i = 0; i < bno055_acc_range.len; i++)
10324aefe1c2SAndrea Merello 		len += sysfs_emit_at(buf, len, "%d ", bno055_acc_range.vals[i]);
10334aefe1c2SAndrea Merello 	buf[len - 1] = '\n';
10344aefe1c2SAndrea Merello 
10354aefe1c2SAndrea Merello 	return len;
10364aefe1c2SAndrea Merello }
10374aefe1c2SAndrea Merello 
fusion_enable_show(struct device * dev,struct device_attribute * attr,char * buf)10384aefe1c2SAndrea Merello static ssize_t fusion_enable_show(struct device *dev,
10394aefe1c2SAndrea Merello 				  struct device_attribute *attr,
10404aefe1c2SAndrea Merello 				  char *buf)
10414aefe1c2SAndrea Merello {
10424aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev));
10434aefe1c2SAndrea Merello 
10444aefe1c2SAndrea Merello 	return sysfs_emit(buf, "%d\n",
10454aefe1c2SAndrea Merello 			  priv->operation_mode != BNO055_OPR_MODE_AMG);
10464aefe1c2SAndrea Merello }
10474aefe1c2SAndrea Merello 
fusion_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)10484aefe1c2SAndrea Merello static ssize_t fusion_enable_store(struct device *dev,
10494aefe1c2SAndrea Merello 				   struct device_attribute *attr,
10504aefe1c2SAndrea Merello 				   const char *buf, size_t len)
10514aefe1c2SAndrea Merello {
10524aefe1c2SAndrea Merello 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
10534aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(indio_dev);
10544aefe1c2SAndrea Merello 	bool en;
10554aefe1c2SAndrea Merello 	int ret;
10564aefe1c2SAndrea Merello 
10574aefe1c2SAndrea Merello 	if (indio_dev->active_scan_mask &&
10584aefe1c2SAndrea Merello 	    !bitmap_empty(indio_dev->active_scan_mask, _BNO055_SCAN_MAX))
10594aefe1c2SAndrea Merello 		return -EBUSY;
10604aefe1c2SAndrea Merello 
10614aefe1c2SAndrea Merello 	ret = kstrtobool(buf, &en);
10624aefe1c2SAndrea Merello 	if (ret)
10634aefe1c2SAndrea Merello 		return -EINVAL;
10644aefe1c2SAndrea Merello 
10654aefe1c2SAndrea Merello 	if (!en)
10664aefe1c2SAndrea Merello 		return bno055_operation_mode_set(priv, BNO055_OPR_MODE_AMG) ?: len;
10674aefe1c2SAndrea Merello 
10684aefe1c2SAndrea Merello 	/*
10694aefe1c2SAndrea Merello 	 * Coming from AMG means the FMC was off, just switch to fusion but
10704aefe1c2SAndrea Merello 	 * don't change anything that doesn't belong to us (i.e let FMC stay off).
10714aefe1c2SAndrea Merello 	 * Coming from any other fusion mode means we don't need to do anything.
10724aefe1c2SAndrea Merello 	 */
10734aefe1c2SAndrea Merello 	if (priv->operation_mode == BNO055_OPR_MODE_AMG)
10744aefe1c2SAndrea Merello 		return  bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF) ?: len;
10754aefe1c2SAndrea Merello 
10764aefe1c2SAndrea Merello 	return len;
10774aefe1c2SAndrea Merello }
10784aefe1c2SAndrea Merello 
in_magn_calibration_fast_enable_show(struct device * dev,struct device_attribute * attr,char * buf)10794aefe1c2SAndrea Merello static ssize_t in_magn_calibration_fast_enable_show(struct device *dev,
10804aefe1c2SAndrea Merello 						    struct device_attribute *attr,
10814aefe1c2SAndrea Merello 						    char *buf)
10824aefe1c2SAndrea Merello {
10834aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev));
10844aefe1c2SAndrea Merello 
10854aefe1c2SAndrea Merello 	return sysfs_emit(buf, "%d\n",
10864aefe1c2SAndrea Merello 			  priv->operation_mode == BNO055_OPR_MODE_FUSION);
10874aefe1c2SAndrea Merello }
10884aefe1c2SAndrea Merello 
in_magn_calibration_fast_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)10894aefe1c2SAndrea Merello static ssize_t in_magn_calibration_fast_enable_store(struct device *dev,
10904aefe1c2SAndrea Merello 						     struct device_attribute *attr,
10914aefe1c2SAndrea Merello 						     const char *buf, size_t len)
10924aefe1c2SAndrea Merello {
10934aefe1c2SAndrea Merello 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
10944aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(indio_dev);
10954aefe1c2SAndrea Merello 	int ret;
10964aefe1c2SAndrea Merello 
10974aefe1c2SAndrea Merello 	if (indio_dev->active_scan_mask &&
10984aefe1c2SAndrea Merello 	    !bitmap_empty(indio_dev->active_scan_mask, _BNO055_SCAN_MAX))
10994aefe1c2SAndrea Merello 		return -EBUSY;
11004aefe1c2SAndrea Merello 
11014aefe1c2SAndrea Merello 	if (sysfs_streq(buf, "0")) {
11024aefe1c2SAndrea Merello 		if (priv->operation_mode == BNO055_OPR_MODE_FUSION) {
11034aefe1c2SAndrea Merello 			ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF);
11044aefe1c2SAndrea Merello 			if (ret)
11054aefe1c2SAndrea Merello 				return ret;
11064aefe1c2SAndrea Merello 		}
11074aefe1c2SAndrea Merello 	} else {
11084aefe1c2SAndrea Merello 		if (priv->operation_mode == BNO055_OPR_MODE_AMG)
11094aefe1c2SAndrea Merello 			return -EINVAL;
11104aefe1c2SAndrea Merello 
11114aefe1c2SAndrea Merello 		if (priv->operation_mode != BNO055_OPR_MODE_FUSION) {
11124aefe1c2SAndrea Merello 			ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION);
11134aefe1c2SAndrea Merello 			if (ret)
11144aefe1c2SAndrea Merello 				return ret;
11154aefe1c2SAndrea Merello 		}
11164aefe1c2SAndrea Merello 	}
11174aefe1c2SAndrea Merello 
11184aefe1c2SAndrea Merello 	return len;
11194aefe1c2SAndrea Merello }
11204aefe1c2SAndrea Merello 
in_accel_range_raw_show(struct device * dev,struct device_attribute * attr,char * buf)11214aefe1c2SAndrea Merello static ssize_t in_accel_range_raw_show(struct device *dev,
11224aefe1c2SAndrea Merello 				       struct device_attribute *attr,
11234aefe1c2SAndrea Merello 				       char *buf)
11244aefe1c2SAndrea Merello {
11254aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev));
11264aefe1c2SAndrea Merello 	int val;
11274aefe1c2SAndrea Merello 	int ret;
11284aefe1c2SAndrea Merello 
11294aefe1c2SAndrea Merello 	ret = bno055_get_regmask(priv, &val, NULL,
11304aefe1c2SAndrea Merello 				 BNO055_ACC_CONFIG_REG,
11314aefe1c2SAndrea Merello 				 BNO055_ACC_CONFIG_RANGE_MASK,
11324aefe1c2SAndrea Merello 				 &bno055_acc_range);
11334aefe1c2SAndrea Merello 	if (ret < 0)
11344aefe1c2SAndrea Merello 		return ret;
11354aefe1c2SAndrea Merello 
11364aefe1c2SAndrea Merello 	return sysfs_emit(buf, "%d\n", val);
11374aefe1c2SAndrea Merello }
11384aefe1c2SAndrea Merello 
in_accel_range_raw_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)11394aefe1c2SAndrea Merello static ssize_t in_accel_range_raw_store(struct device *dev,
11404aefe1c2SAndrea Merello 					struct device_attribute *attr,
11414aefe1c2SAndrea Merello 					const char *buf, size_t len)
11424aefe1c2SAndrea Merello {
11434aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev));
11444aefe1c2SAndrea Merello 	unsigned long val;
11454aefe1c2SAndrea Merello 	int ret;
11464aefe1c2SAndrea Merello 
11474aefe1c2SAndrea Merello 	ret = kstrtoul(buf, 10, &val);
11484aefe1c2SAndrea Merello 	if (ret)
11494aefe1c2SAndrea Merello 		return ret;
11504aefe1c2SAndrea Merello 
11514aefe1c2SAndrea Merello 	mutex_lock(&priv->lock);
11524aefe1c2SAndrea Merello 	ret = bno055_set_regmask(priv, val, 0,
11534aefe1c2SAndrea Merello 				 BNO055_ACC_CONFIG_REG,
11544aefe1c2SAndrea Merello 				 BNO055_ACC_CONFIG_RANGE_MASK,
11554aefe1c2SAndrea Merello 				 &bno055_acc_range);
11564aefe1c2SAndrea Merello 	mutex_unlock(&priv->lock);
11574aefe1c2SAndrea Merello 
11584aefe1c2SAndrea Merello 	return ret ?: len;
11594aefe1c2SAndrea Merello }
11604aefe1c2SAndrea Merello 
bno055_get_calib_status(struct device * dev,char * buf,int which)11614aefe1c2SAndrea Merello static ssize_t bno055_get_calib_status(struct device *dev, char *buf, int which)
11624aefe1c2SAndrea Merello {
11634aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev));
11644aefe1c2SAndrea Merello 	int calib;
11654aefe1c2SAndrea Merello 	int ret;
11664aefe1c2SAndrea Merello 	int val;
11674aefe1c2SAndrea Merello 
11684aefe1c2SAndrea Merello 	if (priv->operation_mode == BNO055_OPR_MODE_AMG ||
11694aefe1c2SAndrea Merello 	    (priv->operation_mode == BNO055_OPR_MODE_FUSION_FMC_OFF &&
11704aefe1c2SAndrea Merello 	     which == BNO055_CALIB_STAT_MAGN_SHIFT)) {
11714aefe1c2SAndrea Merello 		calib = 0;
11724aefe1c2SAndrea Merello 	} else {
11734aefe1c2SAndrea Merello 		mutex_lock(&priv->lock);
11744aefe1c2SAndrea Merello 		ret = regmap_read(priv->regmap, BNO055_CALIB_STAT_REG, &val);
11754aefe1c2SAndrea Merello 		mutex_unlock(&priv->lock);
11764aefe1c2SAndrea Merello 
11774aefe1c2SAndrea Merello 		if (ret)
11784aefe1c2SAndrea Merello 			return -EIO;
11794aefe1c2SAndrea Merello 
11804aefe1c2SAndrea Merello 		calib = ((val >> which) & GENMASK(1, 0)) + 1;
11814aefe1c2SAndrea Merello 	}
11824aefe1c2SAndrea Merello 
11834aefe1c2SAndrea Merello 	return sysfs_emit(buf, "%d\n", calib);
11844aefe1c2SAndrea Merello }
11854aefe1c2SAndrea Merello 
serialnumber_show(struct device * dev,struct device_attribute * attr,char * buf)11864aefe1c2SAndrea Merello static ssize_t serialnumber_show(struct device *dev,
11874aefe1c2SAndrea Merello 				 struct device_attribute *attr,
11884aefe1c2SAndrea Merello 				 char *buf)
11894aefe1c2SAndrea Merello {
11904aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev));
11914aefe1c2SAndrea Merello 
11924aefe1c2SAndrea Merello 	return sysfs_emit(buf, "%*ph\n", BNO055_UID_LEN, priv->uid);
11934aefe1c2SAndrea Merello }
11944aefe1c2SAndrea Merello 
calibration_data_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)11954aefe1c2SAndrea Merello static ssize_t calibration_data_read(struct file *filp, struct kobject *kobj,
11964aefe1c2SAndrea Merello 				     struct bin_attribute *bin_attr, char *buf,
11974aefe1c2SAndrea Merello 				     loff_t pos, size_t count)
11984aefe1c2SAndrea Merello {
11994aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(dev_to_iio_dev(kobj_to_dev(kobj)));
12004aefe1c2SAndrea Merello 	u8 data[BNO055_CALDATA_LEN];
12014aefe1c2SAndrea Merello 	int ret;
12024aefe1c2SAndrea Merello 
12034aefe1c2SAndrea Merello 	/*
12044aefe1c2SAndrea Merello 	 * Calibration data is volatile; reading it in chunks will possibly
12054aefe1c2SAndrea Merello 	 * results in inconsistent data. We require the user to read the whole
12064aefe1c2SAndrea Merello 	 * blob in a single chunk
12074aefe1c2SAndrea Merello 	 */
12084aefe1c2SAndrea Merello 	if (count < BNO055_CALDATA_LEN || pos)
12094aefe1c2SAndrea Merello 		return -EINVAL;
12104aefe1c2SAndrea Merello 
12114aefe1c2SAndrea Merello 	mutex_lock(&priv->lock);
12124aefe1c2SAndrea Merello 	ret = bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG);
12134aefe1c2SAndrea Merello 	if (ret)
12144aefe1c2SAndrea Merello 		goto exit_unlock;
12154aefe1c2SAndrea Merello 
12164aefe1c2SAndrea Merello 	ret = regmap_bulk_read(priv->regmap, BNO055_CALDATA_START, data,
12174aefe1c2SAndrea Merello 			       BNO055_CALDATA_LEN);
12184aefe1c2SAndrea Merello 	if (ret)
12194aefe1c2SAndrea Merello 		goto exit_unlock;
12204aefe1c2SAndrea Merello 
12214aefe1c2SAndrea Merello 	ret = bno055_operation_mode_do_set(priv, priv->operation_mode);
12224aefe1c2SAndrea Merello 	if (ret)
12234aefe1c2SAndrea Merello 		goto exit_unlock;
12244aefe1c2SAndrea Merello 
12254aefe1c2SAndrea Merello 	memcpy(buf, data, BNO055_CALDATA_LEN);
12264aefe1c2SAndrea Merello 
12274aefe1c2SAndrea Merello 	ret = BNO055_CALDATA_LEN;
12284aefe1c2SAndrea Merello exit_unlock:
12294aefe1c2SAndrea Merello 	mutex_unlock(&priv->lock);
12304aefe1c2SAndrea Merello 	return ret;
12314aefe1c2SAndrea Merello }
12324aefe1c2SAndrea Merello 
sys_calibration_auto_status_show(struct device * dev,struct device_attribute * a,char * buf)12334aefe1c2SAndrea Merello static ssize_t sys_calibration_auto_status_show(struct device *dev,
12344aefe1c2SAndrea Merello 						struct device_attribute *a,
12354aefe1c2SAndrea Merello 						char *buf)
12364aefe1c2SAndrea Merello {
12374aefe1c2SAndrea Merello 	return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_SYS_SHIFT);
12384aefe1c2SAndrea Merello }
12394aefe1c2SAndrea Merello 
in_accel_calibration_auto_status_show(struct device * dev,struct device_attribute * a,char * buf)12404aefe1c2SAndrea Merello static ssize_t in_accel_calibration_auto_status_show(struct device *dev,
12414aefe1c2SAndrea Merello 						     struct device_attribute *a,
12424aefe1c2SAndrea Merello 						     char *buf)
12434aefe1c2SAndrea Merello {
12444aefe1c2SAndrea Merello 	return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_ACCEL_SHIFT);
12454aefe1c2SAndrea Merello }
12464aefe1c2SAndrea Merello 
in_gyro_calibration_auto_status_show(struct device * dev,struct device_attribute * a,char * buf)12474aefe1c2SAndrea Merello static ssize_t in_gyro_calibration_auto_status_show(struct device *dev,
12484aefe1c2SAndrea Merello 						    struct device_attribute *a,
12494aefe1c2SAndrea Merello 						    char *buf)
12504aefe1c2SAndrea Merello {
12514aefe1c2SAndrea Merello 	return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_GYRO_SHIFT);
12524aefe1c2SAndrea Merello }
12534aefe1c2SAndrea Merello 
in_magn_calibration_auto_status_show(struct device * dev,struct device_attribute * a,char * buf)12544aefe1c2SAndrea Merello static ssize_t in_magn_calibration_auto_status_show(struct device *dev,
12554aefe1c2SAndrea Merello 						    struct device_attribute *a,
12564aefe1c2SAndrea Merello 						    char *buf)
12574aefe1c2SAndrea Merello {
12584aefe1c2SAndrea Merello 	return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_MAGN_SHIFT);
12594aefe1c2SAndrea Merello }
12604aefe1c2SAndrea Merello 
bno055_debugfs_reg_access(struct iio_dev * iio_dev,unsigned int reg,unsigned int writeval,unsigned int * readval)12614aefe1c2SAndrea Merello static int bno055_debugfs_reg_access(struct iio_dev *iio_dev, unsigned int reg,
12624aefe1c2SAndrea Merello 				     unsigned int writeval, unsigned int *readval)
12634aefe1c2SAndrea Merello {
12644aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(iio_dev);
12654aefe1c2SAndrea Merello 
12664aefe1c2SAndrea Merello 	if (readval)
12674aefe1c2SAndrea Merello 		return regmap_read(priv->regmap, reg, readval);
12684aefe1c2SAndrea Merello 	else
12694aefe1c2SAndrea Merello 		return regmap_write(priv->regmap, reg, writeval);
12704aefe1c2SAndrea Merello }
12714aefe1c2SAndrea Merello 
bno055_show_fw_version(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)12724aefe1c2SAndrea Merello static ssize_t bno055_show_fw_version(struct file *file, char __user *userbuf,
12734aefe1c2SAndrea Merello 				      size_t count, loff_t *ppos)
12744aefe1c2SAndrea Merello {
12754aefe1c2SAndrea Merello 	struct bno055_priv *priv = file->private_data;
12764aefe1c2SAndrea Merello 	int rev, ver;
12774aefe1c2SAndrea Merello 	char *buf;
12784aefe1c2SAndrea Merello 	int ret;
12794aefe1c2SAndrea Merello 
12804aefe1c2SAndrea Merello 	ret = regmap_read(priv->regmap, BNO055_SW_REV_LSB_REG, &rev);
12814aefe1c2SAndrea Merello 	if (ret)
12824aefe1c2SAndrea Merello 		return ret;
12834aefe1c2SAndrea Merello 
12844aefe1c2SAndrea Merello 	ret = regmap_read(priv->regmap, BNO055_SW_REV_MSB_REG, &ver);
12854aefe1c2SAndrea Merello 	if (ret)
12864aefe1c2SAndrea Merello 		return ret;
12874aefe1c2SAndrea Merello 
12884aefe1c2SAndrea Merello 	buf = kasprintf(GFP_KERNEL, "ver: 0x%x, rev: 0x%x\n", ver, rev);
12894aefe1c2SAndrea Merello 	if (!buf)
12904aefe1c2SAndrea Merello 		return -ENOMEM;
12914aefe1c2SAndrea Merello 
12924aefe1c2SAndrea Merello 	ret = simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
12934aefe1c2SAndrea Merello 	kfree(buf);
12944aefe1c2SAndrea Merello 
12954aefe1c2SAndrea Merello 	return ret;
12964aefe1c2SAndrea Merello }
12974aefe1c2SAndrea Merello 
12984aefe1c2SAndrea Merello static const struct file_operations bno055_fw_version_ops = {
12994aefe1c2SAndrea Merello 	.open = simple_open,
13004aefe1c2SAndrea Merello 	.read = bno055_show_fw_version,
13014aefe1c2SAndrea Merello 	.llseek = default_llseek,
13024aefe1c2SAndrea Merello 	.owner = THIS_MODULE,
13034aefe1c2SAndrea Merello };
13044aefe1c2SAndrea Merello 
bno055_debugfs_remove(void * _priv)13054aefe1c2SAndrea Merello static void bno055_debugfs_remove(void *_priv)
13064aefe1c2SAndrea Merello {
13074aefe1c2SAndrea Merello 	struct bno055_priv *priv = _priv;
13084aefe1c2SAndrea Merello 
13094aefe1c2SAndrea Merello 	debugfs_remove(priv->debugfs);
13104aefe1c2SAndrea Merello 	priv->debugfs = NULL;
13114aefe1c2SAndrea Merello }
13124aefe1c2SAndrea Merello 
bno055_debugfs_init(struct iio_dev * iio_dev)13134aefe1c2SAndrea Merello static void bno055_debugfs_init(struct iio_dev *iio_dev)
13144aefe1c2SAndrea Merello {
13154aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(iio_dev);
13164aefe1c2SAndrea Merello 
13174aefe1c2SAndrea Merello 	priv->debugfs = debugfs_create_file("firmware_version", 0400,
13184aefe1c2SAndrea Merello 					    iio_get_debugfs_dentry(iio_dev),
13194aefe1c2SAndrea Merello 					    priv, &bno055_fw_version_ops);
13204aefe1c2SAndrea Merello 	if (!IS_ERR(priv->debugfs))
13214aefe1c2SAndrea Merello 		devm_add_action_or_reset(priv->dev, bno055_debugfs_remove,
13224aefe1c2SAndrea Merello 					 priv);
13234aefe1c2SAndrea Merello 	if (IS_ERR_OR_NULL(priv->debugfs))
13244aefe1c2SAndrea Merello 		dev_warn(priv->dev, "failed to setup debugfs");
13254aefe1c2SAndrea Merello }
13264aefe1c2SAndrea Merello 
13274aefe1c2SAndrea Merello static IIO_DEVICE_ATTR_RW(fusion_enable, 0);
13284aefe1c2SAndrea Merello static IIO_DEVICE_ATTR_RW(in_magn_calibration_fast_enable, 0);
13294aefe1c2SAndrea Merello static IIO_DEVICE_ATTR_RW(in_accel_range_raw, 0);
13304aefe1c2SAndrea Merello 
13314aefe1c2SAndrea Merello static IIO_DEVICE_ATTR_RO(in_accel_range_raw_available, 0);
13324aefe1c2SAndrea Merello static IIO_DEVICE_ATTR_RO(sys_calibration_auto_status, 0);
13334aefe1c2SAndrea Merello static IIO_DEVICE_ATTR_RO(in_accel_calibration_auto_status, 0);
13344aefe1c2SAndrea Merello static IIO_DEVICE_ATTR_RO(in_gyro_calibration_auto_status, 0);
13354aefe1c2SAndrea Merello static IIO_DEVICE_ATTR_RO(in_magn_calibration_auto_status, 0);
13364aefe1c2SAndrea Merello static IIO_DEVICE_ATTR_RO(serialnumber, 0);
13374aefe1c2SAndrea Merello 
13384aefe1c2SAndrea Merello static struct attribute *bno055_attrs[] = {
13394aefe1c2SAndrea Merello 	&iio_dev_attr_in_accel_range_raw_available.dev_attr.attr,
13404aefe1c2SAndrea Merello 	&iio_dev_attr_in_accel_range_raw.dev_attr.attr,
13414aefe1c2SAndrea Merello 	&iio_dev_attr_fusion_enable.dev_attr.attr,
13424aefe1c2SAndrea Merello 	&iio_dev_attr_in_magn_calibration_fast_enable.dev_attr.attr,
13434aefe1c2SAndrea Merello 	&iio_dev_attr_sys_calibration_auto_status.dev_attr.attr,
13444aefe1c2SAndrea Merello 	&iio_dev_attr_in_accel_calibration_auto_status.dev_attr.attr,
13454aefe1c2SAndrea Merello 	&iio_dev_attr_in_gyro_calibration_auto_status.dev_attr.attr,
13464aefe1c2SAndrea Merello 	&iio_dev_attr_in_magn_calibration_auto_status.dev_attr.attr,
13474aefe1c2SAndrea Merello 	&iio_dev_attr_serialnumber.dev_attr.attr,
13484aefe1c2SAndrea Merello 	NULL
13494aefe1c2SAndrea Merello };
13504aefe1c2SAndrea Merello 
13514aefe1c2SAndrea Merello static BIN_ATTR_RO(calibration_data, BNO055_CALDATA_LEN);
13524aefe1c2SAndrea Merello 
13534aefe1c2SAndrea Merello static struct bin_attribute *bno055_bin_attrs[] = {
13544aefe1c2SAndrea Merello 	&bin_attr_calibration_data,
13554aefe1c2SAndrea Merello 	NULL
13564aefe1c2SAndrea Merello };
13574aefe1c2SAndrea Merello 
13584aefe1c2SAndrea Merello static const struct attribute_group bno055_attrs_group = {
13594aefe1c2SAndrea Merello 	.attrs = bno055_attrs,
13604aefe1c2SAndrea Merello 	.bin_attrs = bno055_bin_attrs,
13614aefe1c2SAndrea Merello };
13624aefe1c2SAndrea Merello 
13634aefe1c2SAndrea Merello static const struct iio_info bno055_info = {
13644aefe1c2SAndrea Merello 	.read_raw_multi = bno055_read_raw_multi,
13654aefe1c2SAndrea Merello 	.read_avail = bno055_read_avail,
13664aefe1c2SAndrea Merello 	.write_raw = bno055_write_raw,
13674aefe1c2SAndrea Merello 	.attrs = &bno055_attrs_group,
13684aefe1c2SAndrea Merello 	.debugfs_reg_access = bno055_debugfs_reg_access,
13694aefe1c2SAndrea Merello };
13704aefe1c2SAndrea Merello 
13714aefe1c2SAndrea Merello /*
13724aefe1c2SAndrea Merello  * Reads len samples from the HW, stores them in buf starting from buf_idx,
13734aefe1c2SAndrea Merello  * and applies mask to cull (skip) unneeded samples.
13744aefe1c2SAndrea Merello  * Updates buf_idx incrementing with the number of stored samples.
13754aefe1c2SAndrea Merello  * Samples from HW are transferred into buf, then in-place copy on buf is
13764aefe1c2SAndrea Merello  * performed in order to cull samples that need to be skipped.
13774aefe1c2SAndrea Merello  * This avoids copies of the first samples until we hit the 1st sample to skip,
13784aefe1c2SAndrea Merello  * and also avoids having an extra bounce buffer.
13794aefe1c2SAndrea Merello  * buf must be able to contain len elements in spite of how many samples we are
13804aefe1c2SAndrea Merello  * going to cull.
13814aefe1c2SAndrea Merello  */
bno055_scan_xfer(struct bno055_priv * priv,int start_ch,int len,unsigned long mask,__le16 * buf,int * buf_idx)13824aefe1c2SAndrea Merello static int bno055_scan_xfer(struct bno055_priv *priv,
13834aefe1c2SAndrea Merello 			    int start_ch, int len, unsigned long mask,
13844aefe1c2SAndrea Merello 			    __le16 *buf, int *buf_idx)
13854aefe1c2SAndrea Merello {
13864aefe1c2SAndrea Merello 	const int base = BNO055_ACC_DATA_X_LSB_REG;
13874aefe1c2SAndrea Merello 	bool quat_in_read = false;
13884aefe1c2SAndrea Merello 	int buf_base = *buf_idx;
13894aefe1c2SAndrea Merello 	__le16 *dst, *src;
13904aefe1c2SAndrea Merello 	int offs_fixup = 0;
13914aefe1c2SAndrea Merello 	int xfer_len = len;
13924aefe1c2SAndrea Merello 	int ret;
13934aefe1c2SAndrea Merello 	int i, n;
13944aefe1c2SAndrea Merello 
13954aefe1c2SAndrea Merello 	if (!mask)
13964aefe1c2SAndrea Merello 		return 0;
13974aefe1c2SAndrea Merello 
13984aefe1c2SAndrea Merello 	/*
13994aefe1c2SAndrea Merello 	 * All channels are made up 1 16-bit sample, except for quaternion that
14004aefe1c2SAndrea Merello 	 * is made up 4 16-bit values.
14014aefe1c2SAndrea Merello 	 * For us the quaternion CH is just like 4 regular CHs.
14024aefe1c2SAndrea Merello 	 * If our read starts past the quaternion make sure to adjust the
14034aefe1c2SAndrea Merello 	 * starting offset; if the quaternion is contained in our scan then make
14044aefe1c2SAndrea Merello 	 * sure to adjust the read len.
14054aefe1c2SAndrea Merello 	 */
14064aefe1c2SAndrea Merello 	if (start_ch > BNO055_SCAN_QUATERNION) {
14074aefe1c2SAndrea Merello 		start_ch += 3;
14084aefe1c2SAndrea Merello 	} else if ((start_ch <= BNO055_SCAN_QUATERNION) &&
14094aefe1c2SAndrea Merello 		 ((start_ch + len) > BNO055_SCAN_QUATERNION)) {
14104aefe1c2SAndrea Merello 		quat_in_read = true;
14114aefe1c2SAndrea Merello 		xfer_len += 3;
14124aefe1c2SAndrea Merello 	}
14134aefe1c2SAndrea Merello 
14144aefe1c2SAndrea Merello 	ret = regmap_bulk_read(priv->regmap,
14154aefe1c2SAndrea Merello 			       base + start_ch * sizeof(__le16),
14164aefe1c2SAndrea Merello 			       buf + buf_base,
14174aefe1c2SAndrea Merello 			       xfer_len * sizeof(__le16));
14184aefe1c2SAndrea Merello 	if (ret)
14194aefe1c2SAndrea Merello 		return ret;
14204aefe1c2SAndrea Merello 
14214aefe1c2SAndrea Merello 	for_each_set_bit(i, &mask, len) {
14224aefe1c2SAndrea Merello 		if (quat_in_read && ((start_ch + i) > BNO055_SCAN_QUATERNION))
14234aefe1c2SAndrea Merello 			offs_fixup = 3;
14244aefe1c2SAndrea Merello 
14254aefe1c2SAndrea Merello 		dst = buf + *buf_idx;
14264aefe1c2SAndrea Merello 		src = buf + buf_base + offs_fixup + i;
14274aefe1c2SAndrea Merello 
14284aefe1c2SAndrea Merello 		n = (start_ch + i == BNO055_SCAN_QUATERNION) ? 4 : 1;
14294aefe1c2SAndrea Merello 
14304aefe1c2SAndrea Merello 		if (dst != src)
14314aefe1c2SAndrea Merello 			memcpy(dst, src, n * sizeof(__le16));
14324aefe1c2SAndrea Merello 
14334aefe1c2SAndrea Merello 		*buf_idx += n;
14344aefe1c2SAndrea Merello 	}
14354aefe1c2SAndrea Merello 	return 0;
14364aefe1c2SAndrea Merello }
14374aefe1c2SAndrea Merello 
bno055_trigger_handler(int irq,void * p)14384aefe1c2SAndrea Merello static irqreturn_t bno055_trigger_handler(int irq, void *p)
14394aefe1c2SAndrea Merello {
14404aefe1c2SAndrea Merello 	struct iio_poll_func *pf = p;
14414aefe1c2SAndrea Merello 	struct iio_dev *iio_dev = pf->indio_dev;
14424aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(iio_dev);
14434aefe1c2SAndrea Merello 	int xfer_start, start, end, prev_end;
14444aefe1c2SAndrea Merello 	unsigned long mask;
14454aefe1c2SAndrea Merello 	int quat_extra_len;
14464aefe1c2SAndrea Merello 	bool first = true;
14474aefe1c2SAndrea Merello 	int buf_idx = 0;
14484aefe1c2SAndrea Merello 	bool thr_hit;
14494aefe1c2SAndrea Merello 	int ret;
14504aefe1c2SAndrea Merello 
14514aefe1c2SAndrea Merello 	mutex_lock(&priv->lock);
14524aefe1c2SAndrea Merello 
14534aefe1c2SAndrea Merello 	/*
14544aefe1c2SAndrea Merello 	 * Walk the bitmap and eventually perform several transfers.
14554aefe1c2SAndrea Merello 	 * Bitmap ones-fields that are separated by gaps <= xfer_burst_break_thr
14564aefe1c2SAndrea Merello 	 * will be included in same transfer.
14574aefe1c2SAndrea Merello 	 * Every time the bitmap contains a gap wider than xfer_burst_break_thr
14584aefe1c2SAndrea Merello 	 * then we split the transfer, skipping the gap.
14594aefe1c2SAndrea Merello 	 */
14604aefe1c2SAndrea Merello 	for_each_set_bitrange(start, end, iio_dev->active_scan_mask,
14614aefe1c2SAndrea Merello 			      iio_dev->masklength) {
14624aefe1c2SAndrea Merello 		/*
14634aefe1c2SAndrea Merello 		 * First transfer will start from the beginning of the first
14644aefe1c2SAndrea Merello 		 * ones-field in the bitmap
14654aefe1c2SAndrea Merello 		 */
14664aefe1c2SAndrea Merello 		if (first) {
14674aefe1c2SAndrea Merello 			xfer_start = start;
14684aefe1c2SAndrea Merello 		} else {
14694aefe1c2SAndrea Merello 			/*
14704aefe1c2SAndrea Merello 			 * We found the next ones-field; check whether to
14714aefe1c2SAndrea Merello 			 * include it in * the current transfer or not (i.e.
14724aefe1c2SAndrea Merello 			 * let's perform the current * transfer and prepare for
14734aefe1c2SAndrea Merello 			 * another one).
14744aefe1c2SAndrea Merello 			 */
14754aefe1c2SAndrea Merello 
14764aefe1c2SAndrea Merello 			/*
14774aefe1c2SAndrea Merello 			 * In case the zeros-gap contains the quaternion bit,
14784aefe1c2SAndrea Merello 			 * then its length is actually 4 words instead of 1
14794aefe1c2SAndrea Merello 			 * (i.e. +3 wrt other channels).
14804aefe1c2SAndrea Merello 			 */
14814aefe1c2SAndrea Merello 			quat_extra_len = ((start > BNO055_SCAN_QUATERNION) &&
14824aefe1c2SAndrea Merello 					  (prev_end <= BNO055_SCAN_QUATERNION)) ? 3 : 0;
14834aefe1c2SAndrea Merello 
14844aefe1c2SAndrea Merello 			/* If the gap is wider than xfer_burst_break_thr then.. */
14854aefe1c2SAndrea Merello 			thr_hit = (start - prev_end + quat_extra_len) >
14864aefe1c2SAndrea Merello 				priv->xfer_burst_break_thr;
14874aefe1c2SAndrea Merello 
14884aefe1c2SAndrea Merello 			/*
14894aefe1c2SAndrea Merello 			 * .. transfer all the data up to the gap. Then set the
14904aefe1c2SAndrea Merello 			 * next transfer start index at right after the gap
14914aefe1c2SAndrea Merello 			 * (i.e. at the start of this ones-field).
14924aefe1c2SAndrea Merello 			 */
14934aefe1c2SAndrea Merello 			if (thr_hit) {
14944aefe1c2SAndrea Merello 				mask = *iio_dev->active_scan_mask >> xfer_start;
14954aefe1c2SAndrea Merello 				ret = bno055_scan_xfer(priv, xfer_start,
14964aefe1c2SAndrea Merello 						       prev_end - xfer_start,
14974aefe1c2SAndrea Merello 						       mask, priv->buf.chans, &buf_idx);
14984aefe1c2SAndrea Merello 				if (ret)
14994aefe1c2SAndrea Merello 					goto done;
15004aefe1c2SAndrea Merello 				xfer_start = start;
15014aefe1c2SAndrea Merello 			}
15024aefe1c2SAndrea Merello 		}
15034aefe1c2SAndrea Merello 		first = false;
15044aefe1c2SAndrea Merello 		prev_end = end;
15054aefe1c2SAndrea Merello 	}
15064aefe1c2SAndrea Merello 
15074aefe1c2SAndrea Merello 	/*
15084aefe1c2SAndrea Merello 	 * We finished walking the bitmap; no more gaps to check for. Just
15094aefe1c2SAndrea Merello 	 * perform the current transfer.
15104aefe1c2SAndrea Merello 	 */
15114aefe1c2SAndrea Merello 	mask = *iio_dev->active_scan_mask >> xfer_start;
15124aefe1c2SAndrea Merello 	ret = bno055_scan_xfer(priv, xfer_start,
15134aefe1c2SAndrea Merello 			       prev_end - xfer_start,
15144aefe1c2SAndrea Merello 			       mask, priv->buf.chans, &buf_idx);
15154aefe1c2SAndrea Merello 
15164aefe1c2SAndrea Merello 	if (!ret)
15174aefe1c2SAndrea Merello 		iio_push_to_buffers_with_timestamp(iio_dev,
15184aefe1c2SAndrea Merello 						   &priv->buf, pf->timestamp);
15194aefe1c2SAndrea Merello done:
15204aefe1c2SAndrea Merello 	mutex_unlock(&priv->lock);
15214aefe1c2SAndrea Merello 	iio_trigger_notify_done(iio_dev->trig);
15224aefe1c2SAndrea Merello 	return IRQ_HANDLED;
15234aefe1c2SAndrea Merello }
15244aefe1c2SAndrea Merello 
bno055_buffer_preenable(struct iio_dev * indio_dev)15254aefe1c2SAndrea Merello static int bno055_buffer_preenable(struct iio_dev *indio_dev)
15264aefe1c2SAndrea Merello {
15274aefe1c2SAndrea Merello 	struct bno055_priv *priv = iio_priv(indio_dev);
15284aefe1c2SAndrea Merello 	const unsigned long fusion_mask =
15294aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_YAW) |
15304aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_ROLL) |
15314aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_PITCH) |
15324aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_QUATERNION) |
15334aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_LIA_X) |
15344aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_LIA_Y) |
15354aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_LIA_Z) |
15364aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_GRAVITY_X) |
15374aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_GRAVITY_Y) |
15384aefe1c2SAndrea Merello 		BIT(BNO055_SCAN_GRAVITY_Z);
15394aefe1c2SAndrea Merello 
15404aefe1c2SAndrea Merello 	if (priv->operation_mode == BNO055_OPR_MODE_AMG &&
15414aefe1c2SAndrea Merello 	    bitmap_intersects(indio_dev->active_scan_mask, &fusion_mask,
15424aefe1c2SAndrea Merello 			      _BNO055_SCAN_MAX))
15434aefe1c2SAndrea Merello 		return -EBUSY;
15444aefe1c2SAndrea Merello 	return 0;
15454aefe1c2SAndrea Merello }
15464aefe1c2SAndrea Merello 
15474aefe1c2SAndrea Merello static const struct iio_buffer_setup_ops bno055_buffer_setup_ops = {
15484aefe1c2SAndrea Merello 	.preenable = bno055_buffer_preenable,
15494aefe1c2SAndrea Merello };
15504aefe1c2SAndrea Merello 
bno055_probe(struct device * dev,struct regmap * regmap,int xfer_burst_break_thr,bool sw_reset)15514aefe1c2SAndrea Merello int bno055_probe(struct device *dev, struct regmap *regmap,
15524aefe1c2SAndrea Merello 		 int xfer_burst_break_thr, bool sw_reset)
15534aefe1c2SAndrea Merello {
15544aefe1c2SAndrea Merello 	const struct firmware *caldata = NULL;
15554aefe1c2SAndrea Merello 	struct bno055_priv *priv;
15564aefe1c2SAndrea Merello 	struct iio_dev *iio_dev;
15574aefe1c2SAndrea Merello 	char *fw_name_buf;
15584aefe1c2SAndrea Merello 	unsigned int val;
15594aefe1c2SAndrea Merello 	int rev, ver;
15604aefe1c2SAndrea Merello 	int ret;
15614aefe1c2SAndrea Merello 
15624aefe1c2SAndrea Merello 	iio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
15634aefe1c2SAndrea Merello 	if (!iio_dev)
15644aefe1c2SAndrea Merello 		return -ENOMEM;
15654aefe1c2SAndrea Merello 
15664aefe1c2SAndrea Merello 	iio_dev->name = "bno055";
15674aefe1c2SAndrea Merello 	priv = iio_priv(iio_dev);
15684aefe1c2SAndrea Merello 	mutex_init(&priv->lock);
15694aefe1c2SAndrea Merello 	priv->regmap = regmap;
15704aefe1c2SAndrea Merello 	priv->dev = dev;
15714aefe1c2SAndrea Merello 	priv->xfer_burst_break_thr = xfer_burst_break_thr;
15724aefe1c2SAndrea Merello 	priv->sw_reset = sw_reset;
15734aefe1c2SAndrea Merello 
15744aefe1c2SAndrea Merello 	priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
15754aefe1c2SAndrea Merello 	if (IS_ERR(priv->reset_gpio))
15764aefe1c2SAndrea Merello 		return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), "Failed to get reset GPIO\n");
15774aefe1c2SAndrea Merello 
15784aefe1c2SAndrea Merello 	priv->clk = devm_clk_get_optional_enabled(dev, "clk");
15794aefe1c2SAndrea Merello 	if (IS_ERR(priv->clk))
15804aefe1c2SAndrea Merello 		return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get CLK\n");
15814aefe1c2SAndrea Merello 
15824aefe1c2SAndrea Merello 	if (priv->reset_gpio) {
15834aefe1c2SAndrea Merello 		usleep_range(5000, 10000);
15844aefe1c2SAndrea Merello 		gpiod_set_value_cansleep(priv->reset_gpio, 1);
15854aefe1c2SAndrea Merello 		usleep_range(650000, 750000);
15864aefe1c2SAndrea Merello 	} else if (!sw_reset) {
15874aefe1c2SAndrea Merello 		dev_warn(dev, "No usable reset method; IMU may be unreliable\n");
15884aefe1c2SAndrea Merello 	}
15894aefe1c2SAndrea Merello 
15904aefe1c2SAndrea Merello 	ret = regmap_read(priv->regmap, BNO055_CHIP_ID_REG, &val);
15914aefe1c2SAndrea Merello 	if (ret)
15924aefe1c2SAndrea Merello 		return ret;
15934aefe1c2SAndrea Merello 
15944aefe1c2SAndrea Merello 	if (val != BNO055_CHIP_ID_MAGIC)
15954aefe1c2SAndrea Merello 		dev_warn(dev, "Unrecognized chip ID 0x%x\n", val);
15964aefe1c2SAndrea Merello 
15974aefe1c2SAndrea Merello 	/*
15984aefe1c2SAndrea Merello 	 * In case we haven't a HW reset pin, we can still reset the chip via
15994aefe1c2SAndrea Merello 	 * register write. This is probably nonsense in case we can't even
16004aefe1c2SAndrea Merello 	 * communicate with the chip or the chip isn't the one we expect (i.e.
16014aefe1c2SAndrea Merello 	 * we don't write to unknown chips), so we perform SW reset only after
16024aefe1c2SAndrea Merello 	 * chip magic ID check
16034aefe1c2SAndrea Merello 	 */
16044aefe1c2SAndrea Merello 	if (!priv->reset_gpio) {
16054aefe1c2SAndrea Merello 		ret = bno055_system_reset(priv);
16064aefe1c2SAndrea Merello 		if (ret)
16074aefe1c2SAndrea Merello 			return ret;
16084aefe1c2SAndrea Merello 	}
16094aefe1c2SAndrea Merello 
16104aefe1c2SAndrea Merello 	ret = regmap_read(priv->regmap, BNO055_SW_REV_LSB_REG, &rev);
16114aefe1c2SAndrea Merello 	if (ret)
16124aefe1c2SAndrea Merello 		return ret;
16134aefe1c2SAndrea Merello 
16144aefe1c2SAndrea Merello 	ret = regmap_read(priv->regmap, BNO055_SW_REV_MSB_REG, &ver);
16154aefe1c2SAndrea Merello 	if (ret)
16164aefe1c2SAndrea Merello 		return ret;
16174aefe1c2SAndrea Merello 
16184aefe1c2SAndrea Merello 	/*
16194aefe1c2SAndrea Merello 	 * The stock FW version contains a bug (see comment at the beginning of
16204aefe1c2SAndrea Merello 	 * this file) that causes the anglvel scale to be changed depending on
16214aefe1c2SAndrea Merello 	 * the chip range setting. We workaround this, but we don't know what
16224aefe1c2SAndrea Merello 	 * other FW versions might do.
16234aefe1c2SAndrea Merello 	 */
16244aefe1c2SAndrea Merello 	if (ver != 0x3 || rev != 0x11)
16254aefe1c2SAndrea Merello 		dev_warn(dev, "Untested firmware version. Anglvel scale may not work as expected\n");
16264aefe1c2SAndrea Merello 
16274aefe1c2SAndrea Merello 	ret = regmap_bulk_read(priv->regmap, BNO055_UID_LOWER_REG,
16284aefe1c2SAndrea Merello 			       priv->uid, BNO055_UID_LEN);
16294aefe1c2SAndrea Merello 	if (ret)
16304aefe1c2SAndrea Merello 		return ret;
16314aefe1c2SAndrea Merello 
16324aefe1c2SAndrea Merello 	/* Sensor calibration data */
16334aefe1c2SAndrea Merello 	fw_name_buf = kasprintf(GFP_KERNEL, BNO055_FW_UID_FMT,
16344aefe1c2SAndrea Merello 				BNO055_UID_LEN, priv->uid);
16354aefe1c2SAndrea Merello 	if (!fw_name_buf)
16364aefe1c2SAndrea Merello 		return -ENOMEM;
16374aefe1c2SAndrea Merello 
16384aefe1c2SAndrea Merello 	ret = request_firmware(&caldata, fw_name_buf, dev);
16394aefe1c2SAndrea Merello 	kfree(fw_name_buf);
16404aefe1c2SAndrea Merello 	if (ret)
16414aefe1c2SAndrea Merello 		ret = request_firmware(&caldata, BNO055_FW_GENERIC_NAME, dev);
16424aefe1c2SAndrea Merello 	if (ret) {
16434aefe1c2SAndrea Merello 		dev_notice(dev, "Calibration file load failed. See instruction in kernel Documentation/iio/bno055.rst\n");
16444aefe1c2SAndrea Merello 		ret = bno055_init(priv, NULL, 0);
16454aefe1c2SAndrea Merello 	} else {
16464aefe1c2SAndrea Merello 		ret = bno055_init(priv, caldata->data, caldata->size);
16474aefe1c2SAndrea Merello 		release_firmware(caldata);
16484aefe1c2SAndrea Merello 	}
16494aefe1c2SAndrea Merello 	if (ret)
16504aefe1c2SAndrea Merello 		return ret;
16514aefe1c2SAndrea Merello 
16524aefe1c2SAndrea Merello 	priv->operation_mode = BNO055_OPR_MODE_FUSION;
16534aefe1c2SAndrea Merello 	ret = bno055_operation_mode_do_set(priv, priv->operation_mode);
16544aefe1c2SAndrea Merello 	if (ret)
16554aefe1c2SAndrea Merello 		return ret;
16564aefe1c2SAndrea Merello 
16574aefe1c2SAndrea Merello 	ret = devm_add_action_or_reset(dev, bno055_uninit, priv);
16584aefe1c2SAndrea Merello 	if (ret)
16594aefe1c2SAndrea Merello 		return ret;
16604aefe1c2SAndrea Merello 
16614aefe1c2SAndrea Merello 	iio_dev->channels = bno055_channels;
16624aefe1c2SAndrea Merello 	iio_dev->num_channels = ARRAY_SIZE(bno055_channels);
16634aefe1c2SAndrea Merello 	iio_dev->info = &bno055_info;
16644aefe1c2SAndrea Merello 	iio_dev->modes = INDIO_DIRECT_MODE;
16654aefe1c2SAndrea Merello 
16664aefe1c2SAndrea Merello 	ret = devm_iio_triggered_buffer_setup(dev, iio_dev,
16674aefe1c2SAndrea Merello 					      iio_pollfunc_store_time,
16684aefe1c2SAndrea Merello 					      bno055_trigger_handler,
16694aefe1c2SAndrea Merello 					      &bno055_buffer_setup_ops);
16704aefe1c2SAndrea Merello 	if (ret)
16714aefe1c2SAndrea Merello 		return ret;
16724aefe1c2SAndrea Merello 
16734aefe1c2SAndrea Merello 	ret = devm_iio_device_register(dev, iio_dev);
16744aefe1c2SAndrea Merello 	if (ret)
16754aefe1c2SAndrea Merello 		return ret;
16764aefe1c2SAndrea Merello 
16774aefe1c2SAndrea Merello 	bno055_debugfs_init(iio_dev);
16784aefe1c2SAndrea Merello 
16794aefe1c2SAndrea Merello 	return 0;
16804aefe1c2SAndrea Merello }
16814aefe1c2SAndrea Merello EXPORT_SYMBOL_NS_GPL(bno055_probe, IIO_BNO055);
16824aefe1c2SAndrea Merello 
16834aefe1c2SAndrea Merello MODULE_AUTHOR("Andrea Merello <andrea.merello@iit.it>");
16844aefe1c2SAndrea Merello MODULE_DESCRIPTION("Bosch BNO055 driver");
16854aefe1c2SAndrea Merello MODULE_LICENSE("GPL");
1686