18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PNI RM3100 3-axis geomagnetic sensor driver core.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2018 Song Qiang <songqiang1304521@gmail.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * User Manual available at
88c2ecf20Sopenharmony_ci * <https://www.pnicorp.com/download/rm3100-user-manual/>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * TODO: event generation, pm.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h>
198c2ecf20Sopenharmony_ci#include <linux/iio/iio.h>
208c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h>
218c2ecf20Sopenharmony_ci#include <linux/iio/trigger.h>
228c2ecf20Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
238c2ecf20Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "rm3100.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* Cycle Count Registers. */
308c2ecf20Sopenharmony_ci#define RM3100_REG_CC_X			0x05
318c2ecf20Sopenharmony_ci#define RM3100_REG_CC_Y			0x07
328c2ecf20Sopenharmony_ci#define RM3100_REG_CC_Z			0x09
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Poll Measurement Mode register. */
358c2ecf20Sopenharmony_ci#define RM3100_REG_POLL			0x00
368c2ecf20Sopenharmony_ci#define		RM3100_POLL_X		BIT(4)
378c2ecf20Sopenharmony_ci#define		RM3100_POLL_Y		BIT(5)
388c2ecf20Sopenharmony_ci#define		RM3100_POLL_Z		BIT(6)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* Continuous Measurement Mode register. */
418c2ecf20Sopenharmony_ci#define RM3100_REG_CMM			0x01
428c2ecf20Sopenharmony_ci#define		RM3100_CMM_START	BIT(0)
438c2ecf20Sopenharmony_ci#define		RM3100_CMM_X		BIT(4)
448c2ecf20Sopenharmony_ci#define		RM3100_CMM_Y		BIT(5)
458c2ecf20Sopenharmony_ci#define		RM3100_CMM_Z		BIT(6)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/* TiMe Rate Configuration register. */
488c2ecf20Sopenharmony_ci#define RM3100_REG_TMRC			0x0B
498c2ecf20Sopenharmony_ci#define RM3100_TMRC_OFFSET		0x92
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* Result Status register. */
528c2ecf20Sopenharmony_ci#define RM3100_REG_STATUS		0x34
538c2ecf20Sopenharmony_ci#define		RM3100_STATUS_DRDY	BIT(7)
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* Measurement result registers. */
568c2ecf20Sopenharmony_ci#define RM3100_REG_MX2			0x24
578c2ecf20Sopenharmony_ci#define RM3100_REG_MY2			0x27
588c2ecf20Sopenharmony_ci#define RM3100_REG_MZ2			0x2a
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define RM3100_W_REG_START		RM3100_REG_POLL
618c2ecf20Sopenharmony_ci#define RM3100_W_REG_END		RM3100_REG_TMRC
628c2ecf20Sopenharmony_ci#define RM3100_R_REG_START		RM3100_REG_POLL
638c2ecf20Sopenharmony_ci#define RM3100_R_REG_END		RM3100_REG_STATUS
648c2ecf20Sopenharmony_ci#define RM3100_V_REG_START		RM3100_REG_POLL
658c2ecf20Sopenharmony_ci#define RM3100_V_REG_END		RM3100_REG_STATUS
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/*
688c2ecf20Sopenharmony_ci * This is computed by hand, is the sum of channel storage bits and padding
698c2ecf20Sopenharmony_ci * bits, which is 4+4+4+12=24 in here.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_ci#define RM3100_SCAN_BYTES		24
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define RM3100_CMM_AXIS_SHIFT		4
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistruct rm3100_data {
768c2ecf20Sopenharmony_ci	struct regmap *regmap;
778c2ecf20Sopenharmony_ci	struct completion measuring_done;
788c2ecf20Sopenharmony_ci	bool use_interrupt;
798c2ecf20Sopenharmony_ci	int conversion_time;
808c2ecf20Sopenharmony_ci	int scale;
818c2ecf20Sopenharmony_ci	/* Ensure naturally aligned timestamp */
828c2ecf20Sopenharmony_ci	u8 buffer[RM3100_SCAN_BYTES] __aligned(8);
838c2ecf20Sopenharmony_ci	struct iio_trigger *drdy_trig;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/*
868c2ecf20Sopenharmony_ci	 * This lock is for protecting the consistency of series of i2c
878c2ecf20Sopenharmony_ci	 * operations, that is, to make sure a measurement process will
888c2ecf20Sopenharmony_ci	 * not be interrupted by a set frequency operation, which should
898c2ecf20Sopenharmony_ci	 * be taken where a series of i2c operation starts, released where
908c2ecf20Sopenharmony_ci	 * the operation ends.
918c2ecf20Sopenharmony_ci	 */
928c2ecf20Sopenharmony_ci	struct mutex lock;
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic const struct regmap_range rm3100_readable_ranges[] = {
968c2ecf20Sopenharmony_ci	regmap_reg_range(RM3100_R_REG_START, RM3100_R_REG_END),
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciconst struct regmap_access_table rm3100_readable_table = {
1008c2ecf20Sopenharmony_ci	.yes_ranges = rm3100_readable_ranges,
1018c2ecf20Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(rm3100_readable_ranges),
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rm3100_readable_table);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic const struct regmap_range rm3100_writable_ranges[] = {
1068c2ecf20Sopenharmony_ci	regmap_reg_range(RM3100_W_REG_START, RM3100_W_REG_END),
1078c2ecf20Sopenharmony_ci};
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ciconst struct regmap_access_table rm3100_writable_table = {
1108c2ecf20Sopenharmony_ci	.yes_ranges = rm3100_writable_ranges,
1118c2ecf20Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(rm3100_writable_ranges),
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rm3100_writable_table);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic const struct regmap_range rm3100_volatile_ranges[] = {
1168c2ecf20Sopenharmony_ci	regmap_reg_range(RM3100_V_REG_START, RM3100_V_REG_END),
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ciconst struct regmap_access_table rm3100_volatile_table = {
1208c2ecf20Sopenharmony_ci	.yes_ranges = rm3100_volatile_ranges,
1218c2ecf20Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(rm3100_volatile_ranges),
1228c2ecf20Sopenharmony_ci};
1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rm3100_volatile_table);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic irqreturn_t rm3100_thread_fn(int irq, void *d)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = d;
1288c2ecf20Sopenharmony_ci	struct rm3100_data *data = iio_priv(indio_dev);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/*
1318c2ecf20Sopenharmony_ci	 * Write operation to any register or read operation
1328c2ecf20Sopenharmony_ci	 * to first byte of results will clear the interrupt.
1338c2ecf20Sopenharmony_ci	 */
1348c2ecf20Sopenharmony_ci	regmap_write(data->regmap, RM3100_REG_POLL, 0);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic irqreturn_t rm3100_irq_handler(int irq, void *d)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = d;
1428c2ecf20Sopenharmony_ci	struct rm3100_data *data = iio_priv(indio_dev);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	switch (indio_dev->currentmode) {
1458c2ecf20Sopenharmony_ci	case INDIO_DIRECT_MODE:
1468c2ecf20Sopenharmony_ci		complete(&data->measuring_done);
1478c2ecf20Sopenharmony_ci		break;
1488c2ecf20Sopenharmony_ci	case INDIO_BUFFER_TRIGGERED:
1498c2ecf20Sopenharmony_ci		iio_trigger_poll(data->drdy_trig);
1508c2ecf20Sopenharmony_ci		break;
1518c2ecf20Sopenharmony_ci	default:
1528c2ecf20Sopenharmony_ci		dev_err(indio_dev->dev.parent,
1538c2ecf20Sopenharmony_ci			"device mode out of control, current mode: %d",
1548c2ecf20Sopenharmony_ci			indio_dev->currentmode);
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	return IRQ_WAKE_THREAD;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic int rm3100_wait_measurement(struct rm3100_data *data)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct regmap *regmap = data->regmap;
1638c2ecf20Sopenharmony_ci	unsigned int val;
1648c2ecf20Sopenharmony_ci	int tries = 20;
1658c2ecf20Sopenharmony_ci	int ret;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	/*
1688c2ecf20Sopenharmony_ci	 * A read cycle of 400kbits i2c bus is about 20us, plus the time
1698c2ecf20Sopenharmony_ci	 * used for scheduling, a read cycle of fast mode of this device
1708c2ecf20Sopenharmony_ci	 * can reach 1.7ms, it may be possible for data to arrive just
1718c2ecf20Sopenharmony_ci	 * after we check the RM3100_REG_STATUS. In this case, irq_handler is
1728c2ecf20Sopenharmony_ci	 * called before measuring_done is reinitialized, it will wait
1738c2ecf20Sopenharmony_ci	 * forever for data that has already been ready.
1748c2ecf20Sopenharmony_ci	 * Reinitialize measuring_done before looking up makes sure we
1758c2ecf20Sopenharmony_ci	 * will always capture interrupt no matter when it happens.
1768c2ecf20Sopenharmony_ci	 */
1778c2ecf20Sopenharmony_ci	if (data->use_interrupt)
1788c2ecf20Sopenharmony_ci		reinit_completion(&data->measuring_done);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	ret = regmap_read(regmap, RM3100_REG_STATUS, &val);
1818c2ecf20Sopenharmony_ci	if (ret < 0)
1828c2ecf20Sopenharmony_ci		return ret;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if ((val & RM3100_STATUS_DRDY) != RM3100_STATUS_DRDY) {
1858c2ecf20Sopenharmony_ci		if (data->use_interrupt) {
1868c2ecf20Sopenharmony_ci			ret = wait_for_completion_timeout(&data->measuring_done,
1878c2ecf20Sopenharmony_ci				msecs_to_jiffies(data->conversion_time));
1888c2ecf20Sopenharmony_ci			if (!ret)
1898c2ecf20Sopenharmony_ci				return -ETIMEDOUT;
1908c2ecf20Sopenharmony_ci		} else {
1918c2ecf20Sopenharmony_ci			do {
1928c2ecf20Sopenharmony_ci				usleep_range(1000, 5000);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci				ret = regmap_read(regmap, RM3100_REG_STATUS,
1958c2ecf20Sopenharmony_ci						  &val);
1968c2ecf20Sopenharmony_ci				if (ret < 0)
1978c2ecf20Sopenharmony_ci					return ret;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci				if (val & RM3100_STATUS_DRDY)
2008c2ecf20Sopenharmony_ci					break;
2018c2ecf20Sopenharmony_ci			} while (--tries);
2028c2ecf20Sopenharmony_ci			if (!tries)
2038c2ecf20Sopenharmony_ci				return -ETIMEDOUT;
2048c2ecf20Sopenharmony_ci		}
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci	return 0;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic int rm3100_read_mag(struct rm3100_data *data, int idx, int *val)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	struct regmap *regmap = data->regmap;
2128c2ecf20Sopenharmony_ci	u8 buffer[3];
2138c2ecf20Sopenharmony_ci	int ret;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
2168c2ecf20Sopenharmony_ci	ret = regmap_write(regmap, RM3100_REG_POLL, BIT(4 + idx));
2178c2ecf20Sopenharmony_ci	if (ret < 0)
2188c2ecf20Sopenharmony_ci		goto unlock_return;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	ret = rm3100_wait_measurement(data);
2218c2ecf20Sopenharmony_ci	if (ret < 0)
2228c2ecf20Sopenharmony_ci		goto unlock_return;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * idx, buffer, 3);
2258c2ecf20Sopenharmony_ci	if (ret < 0)
2268c2ecf20Sopenharmony_ci		goto unlock_return;
2278c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	*val = sign_extend32(get_unaligned_be24(&buffer[0]), 23);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return IIO_VAL_INT;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ciunlock_return:
2348c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
2358c2ecf20Sopenharmony_ci	return ret;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci#define RM3100_CHANNEL(axis, idx)					\
2398c2ecf20Sopenharmony_ci	{								\
2408c2ecf20Sopenharmony_ci		.type = IIO_MAGN,					\
2418c2ecf20Sopenharmony_ci		.modified = 1,						\
2428c2ecf20Sopenharmony_ci		.channel2 = IIO_MOD_##axis,				\
2438c2ecf20Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
2448c2ecf20Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
2458c2ecf20Sopenharmony_ci			BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
2468c2ecf20Sopenharmony_ci		.scan_index = idx,					\
2478c2ecf20Sopenharmony_ci		.scan_type = {						\
2488c2ecf20Sopenharmony_ci			.sign = 's',					\
2498c2ecf20Sopenharmony_ci			.realbits = 24,					\
2508c2ecf20Sopenharmony_ci			.storagebits = 32,				\
2518c2ecf20Sopenharmony_ci			.shift = 8,					\
2528c2ecf20Sopenharmony_ci			.endianness = IIO_BE,				\
2538c2ecf20Sopenharmony_ci		},							\
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic const struct iio_chan_spec rm3100_channels[] = {
2578c2ecf20Sopenharmony_ci	RM3100_CHANNEL(X, 0),
2588c2ecf20Sopenharmony_ci	RM3100_CHANNEL(Y, 1),
2598c2ecf20Sopenharmony_ci	RM3100_CHANNEL(Z, 2),
2608c2ecf20Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(3),
2618c2ecf20Sopenharmony_ci};
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
2648c2ecf20Sopenharmony_ci	"600 300 150 75 37 18 9 4.5 2.3 1.2 0.6 0.3 0.015 0.075"
2658c2ecf20Sopenharmony_ci);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic struct attribute *rm3100_attributes[] = {
2688c2ecf20Sopenharmony_ci	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
2698c2ecf20Sopenharmony_ci	NULL,
2708c2ecf20Sopenharmony_ci};
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic const struct attribute_group rm3100_attribute_group = {
2738c2ecf20Sopenharmony_ci	.attrs = rm3100_attributes,
2748c2ecf20Sopenharmony_ci};
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci#define RM3100_SAMP_NUM			14
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/*
2798c2ecf20Sopenharmony_ci * Frequency : rm3100_samp_rates[][0].rm3100_samp_rates[][1]Hz.
2808c2ecf20Sopenharmony_ci * Time between reading: rm3100_sam_rates[][2]ms.
2818c2ecf20Sopenharmony_ci * The first one is actually 1.7ms.
2828c2ecf20Sopenharmony_ci */
2838c2ecf20Sopenharmony_cistatic const int rm3100_samp_rates[RM3100_SAMP_NUM][3] = {
2848c2ecf20Sopenharmony_ci	{600, 0, 2}, {300, 0, 3}, {150, 0, 7}, {75, 0, 13}, {37, 0, 27},
2858c2ecf20Sopenharmony_ci	{18, 0, 55}, {9, 0, 110}, {4, 500000, 220}, {2, 300000, 440},
2868c2ecf20Sopenharmony_ci	{1, 200000, 800}, {0, 600000, 1600}, {0, 300000, 3300},
2878c2ecf20Sopenharmony_ci	{0, 15000, 6700},  {0, 75000, 13000}
2888c2ecf20Sopenharmony_ci};
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int rm3100_get_samp_freq(struct rm3100_data *data, int *val, int *val2)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	unsigned int tmp;
2938c2ecf20Sopenharmony_ci	int ret;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
2968c2ecf20Sopenharmony_ci	ret = regmap_read(data->regmap, RM3100_REG_TMRC, &tmp);
2978c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
2988c2ecf20Sopenharmony_ci	if (ret < 0)
2998c2ecf20Sopenharmony_ci		return ret;
3008c2ecf20Sopenharmony_ci	*val = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][0];
3018c2ecf20Sopenharmony_ci	*val2 = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][1];
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return IIO_VAL_INT_PLUS_MICRO;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic int rm3100_set_cycle_count(struct rm3100_data *data, int val)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	int ret;
3098c2ecf20Sopenharmony_ci	u8 i;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
3128c2ecf20Sopenharmony_ci		ret = regmap_write(data->regmap, RM3100_REG_CC_X + 2 * i, val);
3138c2ecf20Sopenharmony_ci		if (ret < 0)
3148c2ecf20Sopenharmony_ci			return ret;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/*
3188c2ecf20Sopenharmony_ci	 * The scale of this sensor depends on the cycle count value, these
3198c2ecf20Sopenharmony_ci	 * three values are corresponding to the cycle count value 50, 100,
3208c2ecf20Sopenharmony_ci	 * 200. scale = output / gain * 10^4.
3218c2ecf20Sopenharmony_ci	 */
3228c2ecf20Sopenharmony_ci	switch (val) {
3238c2ecf20Sopenharmony_ci	case 50:
3248c2ecf20Sopenharmony_ci		data->scale = 500;
3258c2ecf20Sopenharmony_ci		break;
3268c2ecf20Sopenharmony_ci	case 100:
3278c2ecf20Sopenharmony_ci		data->scale = 263;
3288c2ecf20Sopenharmony_ci		break;
3298c2ecf20Sopenharmony_ci	/*
3308c2ecf20Sopenharmony_ci	 * case 200:
3318c2ecf20Sopenharmony_ci	 * This function will never be called by users' code, so here we
3328c2ecf20Sopenharmony_ci	 * assume that it will never get a wrong parameter.
3338c2ecf20Sopenharmony_ci	 */
3348c2ecf20Sopenharmony_ci	default:
3358c2ecf20Sopenharmony_ci		data->scale = 133;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	return 0;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic int rm3100_set_samp_freq(struct iio_dev *indio_dev, int val, int val2)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct rm3100_data *data = iio_priv(indio_dev);
3448c2ecf20Sopenharmony_ci	struct regmap *regmap = data->regmap;
3458c2ecf20Sopenharmony_ci	unsigned int cycle_count;
3468c2ecf20Sopenharmony_ci	int ret;
3478c2ecf20Sopenharmony_ci	int i;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
3508c2ecf20Sopenharmony_ci	/* All cycle count registers use the same value. */
3518c2ecf20Sopenharmony_ci	ret = regmap_read(regmap, RM3100_REG_CC_X, &cycle_count);
3528c2ecf20Sopenharmony_ci	if (ret < 0)
3538c2ecf20Sopenharmony_ci		goto unlock_return;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	for (i = 0; i < RM3100_SAMP_NUM; i++) {
3568c2ecf20Sopenharmony_ci		if (val == rm3100_samp_rates[i][0] &&
3578c2ecf20Sopenharmony_ci		    val2 == rm3100_samp_rates[i][1])
3588c2ecf20Sopenharmony_ci			break;
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci	if (i == RM3100_SAMP_NUM) {
3618c2ecf20Sopenharmony_ci		ret = -EINVAL;
3628c2ecf20Sopenharmony_ci		goto unlock_return;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	ret = regmap_write(regmap, RM3100_REG_TMRC, i + RM3100_TMRC_OFFSET);
3668c2ecf20Sopenharmony_ci	if (ret < 0)
3678c2ecf20Sopenharmony_ci		goto unlock_return;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* Checking if cycle count registers need changing. */
3708c2ecf20Sopenharmony_ci	if (val == 600 && cycle_count == 200) {
3718c2ecf20Sopenharmony_ci		ret = rm3100_set_cycle_count(data, 100);
3728c2ecf20Sopenharmony_ci		if (ret < 0)
3738c2ecf20Sopenharmony_ci			goto unlock_return;
3748c2ecf20Sopenharmony_ci	} else if (val != 600 && cycle_count == 100) {
3758c2ecf20Sopenharmony_ci		ret = rm3100_set_cycle_count(data, 200);
3768c2ecf20Sopenharmony_ci		if (ret < 0)
3778c2ecf20Sopenharmony_ci			goto unlock_return;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
3818c2ecf20Sopenharmony_ci		/* Writing TMRC registers requires CMM reset. */
3828c2ecf20Sopenharmony_ci		ret = regmap_write(regmap, RM3100_REG_CMM, 0);
3838c2ecf20Sopenharmony_ci		if (ret < 0)
3848c2ecf20Sopenharmony_ci			goto unlock_return;
3858c2ecf20Sopenharmony_ci		ret = regmap_write(data->regmap, RM3100_REG_CMM,
3868c2ecf20Sopenharmony_ci			(*indio_dev->active_scan_mask & 0x7) <<
3878c2ecf20Sopenharmony_ci			RM3100_CMM_AXIS_SHIFT | RM3100_CMM_START);
3888c2ecf20Sopenharmony_ci		if (ret < 0)
3898c2ecf20Sopenharmony_ci			goto unlock_return;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	data->conversion_time = rm3100_samp_rates[i][2] * 2;
3948c2ecf20Sopenharmony_ci	return 0;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ciunlock_return:
3978c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
3988c2ecf20Sopenharmony_ci	return ret;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic int rm3100_read_raw(struct iio_dev *indio_dev,
4028c2ecf20Sopenharmony_ci			   const struct iio_chan_spec *chan,
4038c2ecf20Sopenharmony_ci			   int *val, int *val2, long mask)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	struct rm3100_data *data = iio_priv(indio_dev);
4068c2ecf20Sopenharmony_ci	int ret;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	switch (mask) {
4098c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
4108c2ecf20Sopenharmony_ci		ret = iio_device_claim_direct_mode(indio_dev);
4118c2ecf20Sopenharmony_ci		if (ret < 0)
4128c2ecf20Sopenharmony_ci			return ret;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		ret = rm3100_read_mag(data, chan->scan_index, val);
4158c2ecf20Sopenharmony_ci		iio_device_release_direct_mode(indio_dev);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		return ret;
4188c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
4198c2ecf20Sopenharmony_ci		*val = 0;
4208c2ecf20Sopenharmony_ci		*val2 = data->scale;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		return IIO_VAL_INT_PLUS_MICRO;
4238c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
4248c2ecf20Sopenharmony_ci		return rm3100_get_samp_freq(data, val, val2);
4258c2ecf20Sopenharmony_ci	default:
4268c2ecf20Sopenharmony_ci		return -EINVAL;
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic int rm3100_write_raw(struct iio_dev *indio_dev,
4318c2ecf20Sopenharmony_ci			    struct iio_chan_spec const *chan,
4328c2ecf20Sopenharmony_ci			    int val, int val2, long mask)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	switch (mask) {
4358c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
4368c2ecf20Sopenharmony_ci		return rm3100_set_samp_freq(indio_dev, val, val2);
4378c2ecf20Sopenharmony_ci	default:
4388c2ecf20Sopenharmony_ci		return -EINVAL;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic const struct iio_info rm3100_info = {
4438c2ecf20Sopenharmony_ci	.attrs = &rm3100_attribute_group,
4448c2ecf20Sopenharmony_ci	.read_raw = rm3100_read_raw,
4458c2ecf20Sopenharmony_ci	.write_raw = rm3100_write_raw,
4468c2ecf20Sopenharmony_ci};
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic int rm3100_buffer_preenable(struct iio_dev *indio_dev)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	struct rm3100_data *data = iio_priv(indio_dev);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* Starting channels enabled. */
4538c2ecf20Sopenharmony_ci	return regmap_write(data->regmap, RM3100_REG_CMM,
4548c2ecf20Sopenharmony_ci		(*indio_dev->active_scan_mask & 0x7) << RM3100_CMM_AXIS_SHIFT |
4558c2ecf20Sopenharmony_ci		RM3100_CMM_START);
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic int rm3100_buffer_postdisable(struct iio_dev *indio_dev)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct rm3100_data *data = iio_priv(indio_dev);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	return regmap_write(data->regmap, RM3100_REG_CMM, 0);
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic const struct iio_buffer_setup_ops rm3100_buffer_ops = {
4668c2ecf20Sopenharmony_ci	.preenable = rm3100_buffer_preenable,
4678c2ecf20Sopenharmony_ci	.postdisable = rm3100_buffer_postdisable,
4688c2ecf20Sopenharmony_ci};
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic irqreturn_t rm3100_trigger_handler(int irq, void *p)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	struct iio_poll_func *pf = p;
4738c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
4748c2ecf20Sopenharmony_ci	unsigned long scan_mask = *indio_dev->active_scan_mask;
4758c2ecf20Sopenharmony_ci	unsigned int mask_len = indio_dev->masklength;
4768c2ecf20Sopenharmony_ci	struct rm3100_data *data = iio_priv(indio_dev);
4778c2ecf20Sopenharmony_ci	struct regmap *regmap = data->regmap;
4788c2ecf20Sopenharmony_ci	int ret, i, bit;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
4818c2ecf20Sopenharmony_ci	switch (scan_mask) {
4828c2ecf20Sopenharmony_ci	case BIT(0) | BIT(1) | BIT(2):
4838c2ecf20Sopenharmony_ci		ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9);
4848c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
4858c2ecf20Sopenharmony_ci		if (ret < 0)
4868c2ecf20Sopenharmony_ci			goto done;
4878c2ecf20Sopenharmony_ci		/* Convert XXXYYYZZZxxx to XXXxYYYxZZZx. x for paddings. */
4888c2ecf20Sopenharmony_ci		for (i = 2; i > 0; i--)
4898c2ecf20Sopenharmony_ci			memmove(data->buffer + i * 4, data->buffer + i * 3, 3);
4908c2ecf20Sopenharmony_ci		break;
4918c2ecf20Sopenharmony_ci	case BIT(0) | BIT(1):
4928c2ecf20Sopenharmony_ci		ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 6);
4938c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
4948c2ecf20Sopenharmony_ci		if (ret < 0)
4958c2ecf20Sopenharmony_ci			goto done;
4968c2ecf20Sopenharmony_ci		memmove(data->buffer + 4, data->buffer + 3, 3);
4978c2ecf20Sopenharmony_ci		break;
4988c2ecf20Sopenharmony_ci	case BIT(1) | BIT(2):
4998c2ecf20Sopenharmony_ci		ret = regmap_bulk_read(regmap, RM3100_REG_MY2, data->buffer, 6);
5008c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
5018c2ecf20Sopenharmony_ci		if (ret < 0)
5028c2ecf20Sopenharmony_ci			goto done;
5038c2ecf20Sopenharmony_ci		memmove(data->buffer + 4, data->buffer + 3, 3);
5048c2ecf20Sopenharmony_ci		break;
5058c2ecf20Sopenharmony_ci	case BIT(0) | BIT(2):
5068c2ecf20Sopenharmony_ci		ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9);
5078c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
5088c2ecf20Sopenharmony_ci		if (ret < 0)
5098c2ecf20Sopenharmony_ci			goto done;
5108c2ecf20Sopenharmony_ci		memmove(data->buffer + 4, data->buffer + 6, 3);
5118c2ecf20Sopenharmony_ci		break;
5128c2ecf20Sopenharmony_ci	default:
5138c2ecf20Sopenharmony_ci		for_each_set_bit(bit, &scan_mask, mask_len) {
5148c2ecf20Sopenharmony_ci			ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * bit,
5158c2ecf20Sopenharmony_ci					       data->buffer, 3);
5168c2ecf20Sopenharmony_ci			if (ret < 0) {
5178c2ecf20Sopenharmony_ci				mutex_unlock(&data->lock);
5188c2ecf20Sopenharmony_ci				goto done;
5198c2ecf20Sopenharmony_ci			}
5208c2ecf20Sopenharmony_ci		}
5218c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci	/*
5248c2ecf20Sopenharmony_ci	 * Always using the same buffer so that we wouldn't need to set the
5258c2ecf20Sopenharmony_ci	 * paddings to 0 in case of leaking any data.
5268c2ecf20Sopenharmony_ci	 */
5278c2ecf20Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
5288c2ecf20Sopenharmony_ci					   pf->timestamp);
5298c2ecf20Sopenharmony_cidone:
5308c2ecf20Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ciint rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev;
5388c2ecf20Sopenharmony_ci	struct rm3100_data *data;
5398c2ecf20Sopenharmony_ci	unsigned int tmp;
5408c2ecf20Sopenharmony_ci	int ret;
5418c2ecf20Sopenharmony_ci	int samp_rate_index;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
5448c2ecf20Sopenharmony_ci	if (!indio_dev)
5458c2ecf20Sopenharmony_ci		return -ENOMEM;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	data = iio_priv(indio_dev);
5488c2ecf20Sopenharmony_ci	data->regmap = regmap;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	mutex_init(&data->lock);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	indio_dev->name = "rm3100";
5538c2ecf20Sopenharmony_ci	indio_dev->info = &rm3100_info;
5548c2ecf20Sopenharmony_ci	indio_dev->channels = rm3100_channels;
5558c2ecf20Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(rm3100_channels);
5568c2ecf20Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_TRIGGERED;
5578c2ecf20Sopenharmony_ci	indio_dev->currentmode = INDIO_DIRECT_MODE;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (!irq)
5608c2ecf20Sopenharmony_ci		data->use_interrupt = false;
5618c2ecf20Sopenharmony_ci	else {
5628c2ecf20Sopenharmony_ci		data->use_interrupt = true;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		init_completion(&data->measuring_done);
5658c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(dev,
5668c2ecf20Sopenharmony_ci						irq,
5678c2ecf20Sopenharmony_ci						rm3100_irq_handler,
5688c2ecf20Sopenharmony_ci						rm3100_thread_fn,
5698c2ecf20Sopenharmony_ci						IRQF_TRIGGER_HIGH |
5708c2ecf20Sopenharmony_ci						IRQF_ONESHOT,
5718c2ecf20Sopenharmony_ci						indio_dev->name,
5728c2ecf20Sopenharmony_ci						indio_dev);
5738c2ecf20Sopenharmony_ci		if (ret < 0) {
5748c2ecf20Sopenharmony_ci			dev_err(dev, "request irq line failed.\n");
5758c2ecf20Sopenharmony_ci			return ret;
5768c2ecf20Sopenharmony_ci		}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci		data->drdy_trig = devm_iio_trigger_alloc(dev, "%s-drdy%d",
5798c2ecf20Sopenharmony_ci							 indio_dev->name,
5808c2ecf20Sopenharmony_ci							 indio_dev->id);
5818c2ecf20Sopenharmony_ci		if (!data->drdy_trig)
5828c2ecf20Sopenharmony_ci			return -ENOMEM;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		data->drdy_trig->dev.parent = dev;
5858c2ecf20Sopenharmony_ci		ret = devm_iio_trigger_register(dev, data->drdy_trig);
5868c2ecf20Sopenharmony_ci		if (ret < 0)
5878c2ecf20Sopenharmony_ci			return ret;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
5918c2ecf20Sopenharmony_ci					      &iio_pollfunc_store_time,
5928c2ecf20Sopenharmony_ci					      rm3100_trigger_handler,
5938c2ecf20Sopenharmony_ci					      &rm3100_buffer_ops);
5948c2ecf20Sopenharmony_ci	if (ret < 0)
5958c2ecf20Sopenharmony_ci		return ret;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	ret = regmap_read(regmap, RM3100_REG_TMRC, &tmp);
5988c2ecf20Sopenharmony_ci	if (ret < 0)
5998c2ecf20Sopenharmony_ci		return ret;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	samp_rate_index = tmp - RM3100_TMRC_OFFSET;
6028c2ecf20Sopenharmony_ci	if (samp_rate_index < 0 || samp_rate_index >=  RM3100_SAMP_NUM) {
6038c2ecf20Sopenharmony_ci		dev_err(dev, "The value read from RM3100_REG_TMRC is invalid!\n");
6048c2ecf20Sopenharmony_ci		return -EINVAL;
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci	/* Initializing max wait time, which is double conversion time. */
6078c2ecf20Sopenharmony_ci	data->conversion_time = rm3100_samp_rates[samp_rate_index][2] * 2;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	/* Cycle count values may not be what we want. */
6108c2ecf20Sopenharmony_ci	if ((tmp - RM3100_TMRC_OFFSET) == 0)
6118c2ecf20Sopenharmony_ci		rm3100_set_cycle_count(data, 100);
6128c2ecf20Sopenharmony_ci	else
6138c2ecf20Sopenharmony_ci		rm3100_set_cycle_count(data, 200);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	return devm_iio_device_register(dev, indio_dev);
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rm3100_common_probe);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Song Qiang <songqiang1304521@gmail.com>");
6208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver");
6218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
622