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