Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: accel: add ADXL380 driver

The ADXL380/ADXL382 is a low noise density, low power, 3-axis
accelerometer with selectable measurement ranges. The ADXL380 supports
the +/-4 g, +/-8 g, and +/-16 g ranges, and the ADXL382 supports
+/-15 g, +/-30 g and +/-60 g ranges.
The ADXL380/ADXL382 offers industry leading noise, enabling precision
applications with minimal calibration. The low noise, and low power
ADXL380/ADXL382 enables accurate measurement in an environment with
high vibration, heart sounds and audio.

In addition to its low power consumption, the ADXL380/ADXL382 has many
features to enable true system level performance. These include a
built-in micropower temperature sensor, single / double / triple tap
detection and a state machine to prevent a false triggering. In
addition, the ADXL380/ADXL382 has provisions for external control of
the sampling time and/or an external clock.

Signed-off-by: Ramona Gradinariu <ramona.gradinariu@analog.com>
Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
Link: https://patch.msgid.link/20240708104114.29894-2-antoniu.miclaus@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Antoniu Miclaus and committed by
Jonathan Cameron
df36de13 f1022193

+2095
+4
MAINTAINERS
··· 625 625 S: Supported 626 626 W: https://ez.analog.com/linux-software-drivers 627 627 F: Documentation/devicetree/bindings/iio/accel/adi,adxl380.yaml 628 + F: drivers/iio/accel/adxl380.c 629 + F: drivers/iio/accel/adxl380.h 630 + F: drivers/iio/accel/adxl380_i2c.c 631 + F: drivers/iio/accel/adxl380_spi.c 628 632 629 633 AF8133J THREE-AXIS MAGNETOMETER DRIVER 630 634 M: Ondřej Jirman <megi@xff.cz>
+27
drivers/iio/accel/Kconfig
··· 177 177 To compile this driver as a module, choose M here: the 178 178 module will be called adxl372_i2c. 179 179 180 + config ADXL380 181 + tristate 182 + select IIO_BUFFER 183 + select IIO_TRIGGERED_BUFFER 184 + 185 + config ADXL380_SPI 186 + tristate "Analog Devices ADXL380 3-Axis Accelerometer SPI Driver" 187 + depends on SPI 188 + select ADXL380 189 + select REGMAP_SPI 190 + help 191 + Say yes here to add support for the Analog Devices ADXL380 triaxial 192 + acceleration sensor. 193 + To compile this driver as a module, choose M here: the 194 + module will be called adxl380_spi. 195 + 196 + config ADXL380_I2C 197 + tristate "Analog Devices ADXL380 3-Axis Accelerometer I2C Driver" 198 + depends on I2C 199 + select ADXL380 200 + select REGMAP_I2C 201 + help 202 + Say yes here to add support for the Analog Devices ADXL380 triaxial 203 + acceleration sensor. 204 + To compile this driver as a module, choose M here: the 205 + module will be called adxl380_i2c. 206 + 180 207 config BMA180 181 208 tristate "Bosch BMA023/BMA1x0/BMA250 3-Axis Accelerometer Driver" 182 209 depends on I2C && INPUT_BMA150=n
+3
drivers/iio/accel/Makefile
··· 21 21 obj-$(CONFIG_ADXL372) += adxl372.o 22 22 obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o 23 23 obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o 24 + obj-$(CONFIG_ADXL380) += adxl380.o 25 + obj-$(CONFIG_ADXL380_I2C) += adxl380_i2c.o 26 + obj-$(CONFIG_ADXL380_SPI) += adxl380_spi.o 24 27 obj-$(CONFIG_BMA180) += bma180.o 25 28 obj-$(CONFIG_BMA220) += bma220_spi.o 26 29 obj-$(CONFIG_BMA400) += bma400_core.o
+1905
drivers/iio/accel/adxl380.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * ADXL380 3-Axis Digital Accelerometer core driver 4 + * 5 + * Copyright 2024 Analog Devices Inc. 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/interrupt.h> 10 + #include <linux/irq.h> 11 + #include <linux/module.h> 12 + #include <linux/property.h> 13 + #include <linux/regmap.h> 14 + #include <linux/units.h> 15 + 16 + #include <asm/unaligned.h> 17 + 18 + #include <linux/iio/buffer.h> 19 + #include <linux/iio/events.h> 20 + #include <linux/iio/iio.h> 21 + #include <linux/iio/kfifo_buf.h> 22 + #include <linux/iio/sysfs.h> 23 + 24 + #include <linux/regulator/consumer.h> 25 + 26 + #include "adxl380.h" 27 + 28 + #define ADXL380_ID_VAL 380 29 + #define ADXL382_ID_VAL 382 30 + 31 + #define ADXL380_DEVID_AD_REG 0x00 32 + #define ADLX380_PART_ID_REG 0x02 33 + 34 + #define ADXL380_X_DATA_H_REG 0x15 35 + #define ADXL380_Y_DATA_H_REG 0x17 36 + #define ADXL380_Z_DATA_H_REG 0x19 37 + #define ADXL380_T_DATA_H_REG 0x1B 38 + 39 + #define ADXL380_MISC_0_REG 0x20 40 + #define ADXL380_XL382_MSK BIT(7) 41 + 42 + #define ADXL380_MISC_1_REG 0x21 43 + 44 + #define ADXL380_X_DSM_OFFSET_REG 0x4D 45 + 46 + #define ADXL380_ACT_INACT_CTL_REG 0x37 47 + #define ADXL380_INACT_EN_MSK BIT(2) 48 + #define ADXL380_ACT_EN_MSK BIT(0) 49 + 50 + #define ADXL380_SNSR_AXIS_EN_REG 0x38 51 + #define ADXL380_ACT_INACT_AXIS_EN_MSK GENMASK(2, 0) 52 + 53 + #define ADXL380_THRESH_ACT_H_REG 0x39 54 + #define ADXL380_TIME_ACT_H_REG 0x3B 55 + #define ADXL380_THRESH_INACT_H_REG 0x3E 56 + #define ADXL380_TIME_INACT_H_REG 0x40 57 + #define ADXL380_THRESH_MAX GENMASK(12, 0) 58 + #define ADXL380_TIME_MAX GENMASK(24, 0) 59 + 60 + #define ADXL380_FIFO_CONFIG_0_REG 0x30 61 + #define ADXL380_FIFO_SAMPLES_8_MSK BIT(0) 62 + #define ADXL380_FIFO_MODE_MSK GENMASK(5, 4) 63 + 64 + #define ADXL380_FIFO_DISABLED 0 65 + #define ADXL380_FIFO_NORMAL 1 66 + #define ADXL380_FIFO_STREAMED 2 67 + #define ADXL380_FIFO_TRIGGERED 3 68 + 69 + #define ADXL380_FIFO_CONFIG_1_REG 0x31 70 + #define ADXL380_FIFO_STATUS_0_REG 0x1E 71 + 72 + #define ADXL380_TAP_THRESH_REG 0x43 73 + #define ADXL380_TAP_DUR_REG 0x44 74 + #define ADXL380_TAP_LATENT_REG 0x45 75 + #define ADXL380_TAP_WINDOW_REG 0x46 76 + #define ADXL380_TAP_TIME_MAX GENMASK(7, 0) 77 + 78 + #define ADXL380_TAP_CFG_REG 0x47 79 + #define ADXL380_TAP_AXIS_MSK GENMASK(1, 0) 80 + 81 + #define ADXL380_TRIG_CFG_REG 0x49 82 + #define ADXL380_TRIG_CFG_DEC_2X_MSK BIT(7) 83 + #define ADXL380_TRIG_CFG_SINC_RATE_MSK BIT(6) 84 + 85 + #define ADXL380_FILTER_REG 0x50 86 + #define ADXL380_FILTER_EQ_FILT_MSK BIT(6) 87 + #define ADXL380_FILTER_LPF_MODE_MSK GENMASK(5, 4) 88 + #define ADXL380_FILTER_HPF_PATH_MSK BIT(3) 89 + #define ADXL380_FILTER_HPF_CORNER_MSK GENMASK(2, 0) 90 + 91 + #define ADXL380_OP_MODE_REG 0x26 92 + #define ADXL380_OP_MODE_RANGE_MSK GENMASK(7, 6) 93 + #define ADXL380_OP_MODE_MSK GENMASK(3, 0) 94 + #define ADXL380_OP_MODE_STANDBY 0 95 + #define ADXL380_OP_MODE_HEART_SOUND 1 96 + #define ADXL380_OP_MODE_ULP 2 97 + #define ADXL380_OP_MODE_VLP 3 98 + #define ADXL380_OP_MODE_LP 4 99 + #define ADXL380_OP_MODE_LP_ULP 6 100 + #define ADXL380_OP_MODE_LP_VLP 7 101 + #define ADXL380_OP_MODE_RBW 8 102 + #define ADXL380_OP_MODE_RBW_ULP 10 103 + #define ADXL380_OP_MODE_RBW_VLP 11 104 + #define ADXL380_OP_MODE_HP 12 105 + #define ADXL380_OP_MODE_HP_ULP 14 106 + #define ADXL380_OP_MODE_HP_VLP 15 107 + 108 + #define ADXL380_OP_MODE_4G_RANGE 0 109 + #define ADXL382_OP_MODE_15G_RANGE 0 110 + #define ADXL380_OP_MODE_8G_RANGE 1 111 + #define ADXL382_OP_MODE_30G_RANGE 1 112 + #define ADXL380_OP_MODE_16G_RANGE 2 113 + #define ADXL382_OP_MODE_60G_RANGE 2 114 + 115 + #define ADXL380_DIG_EN_REG 0x27 116 + #define ADXL380_CHAN_EN_MSK(chan) BIT(4 + (chan)) 117 + #define ADXL380_FIFO_EN_MSK BIT(3) 118 + 119 + #define ADXL380_INT0_MAP0_REG 0x2B 120 + #define ADXL380_INT1_MAP0_REG 0x2D 121 + #define ADXL380_INT_MAP0_INACT_INT0_MSK BIT(6) 122 + #define ADXL380_INT_MAP0_ACT_INT0_MSK BIT(5) 123 + #define ADXL380_INT_MAP0_FIFO_WM_INT0_MSK BIT(3) 124 + 125 + #define ADXL380_INT0_MAP1_REG 0x2C 126 + #define ADXL380_INT1_MAP1_REG 0x2E 127 + #define ADXL380_INT_MAP1_DOUBLE_TAP_INT0_MSK BIT(1) 128 + #define ADXL380_INT_MAP1_SINGLE_TAP_INT0_MSK BIT(0) 129 + 130 + #define ADXL380_INT0_REG 0x5D 131 + #define ADXL380_INT0_POL_MSK BIT(7) 132 + 133 + #define ADXL380_RESET_REG 0x2A 134 + #define ADXL380_FIFO_DATA 0x1D 135 + 136 + #define ADXL380_DEVID_AD_VAL 0xAD 137 + #define ADXL380_RESET_CODE 0x52 138 + 139 + #define ADXL380_STATUS_0_REG 0x11 140 + #define ADXL380_STATUS_0_FIFO_FULL_MSK BIT(1) 141 + #define ADXL380_STATUS_0_FIFO_WM_MSK BIT(3) 142 + 143 + #define ADXL380_STATUS_1_INACT_MSK BIT(6) 144 + #define ADXL380_STATUS_1_ACT_MSK BIT(5) 145 + #define ADXL380_STATUS_1_DOUBLE_TAP_MSK BIT(1) 146 + #define ADXL380_STATUS_1_SINGLE_TAP_MSK BIT(0) 147 + 148 + #define ADXL380_FIFO_SAMPLES 315UL 149 + 150 + enum adxl380_channels { 151 + ADXL380_ACCEL_X, 152 + ADXL380_ACCEL_Y, 153 + ADXL380_ACCEL_Z, 154 + ADXL380_TEMP, 155 + ADXL380_CH_NUM 156 + }; 157 + 158 + enum adxl380_axis { 159 + ADXL380_X_AXIS, 160 + ADXL380_Y_AXIS, 161 + ADXL380_Z_AXIS, 162 + }; 163 + 164 + enum adxl380_activity_type { 165 + ADXL380_ACTIVITY, 166 + ADXL380_INACTIVITY, 167 + }; 168 + 169 + enum adxl380_tap_type { 170 + ADXL380_SINGLE_TAP, 171 + ADXL380_DOUBLE_TAP, 172 + }; 173 + 174 + enum adxl380_tap_time_type { 175 + ADXL380_TAP_TIME_LATENT, 176 + ADXL380_TAP_TIME_WINDOW, 177 + }; 178 + 179 + static const int adxl380_range_scale_factor_tbl[] = { 1, 2, 4 }; 180 + 181 + const struct adxl380_chip_info adxl380_chip_info = { 182 + .name = "adxl380", 183 + .chip_id = ADXL380_ID_VAL, 184 + .scale_tbl = { 185 + [ADXL380_OP_MODE_4G_RANGE] = { 0, 1307226 }, 186 + [ADXL380_OP_MODE_8G_RANGE] = { 0, 2615434 }, 187 + [ADXL380_OP_MODE_16G_RANGE] = { 0, 5229886 }, 188 + }, 189 + .samp_freq_tbl = { 8000, 16000, 32000 }, 190 + /* 191 + * The datasheet defines an intercept of 470 LSB at 25 degC 192 + * and a sensitivity of 10.2 LSB/C. 193 + */ 194 + .temp_offset = 25 * 102 / 10 - 470, 195 + 196 + }; 197 + EXPORT_SYMBOL_NS_GPL(adxl380_chip_info, IIO_ADXL380); 198 + 199 + const struct adxl380_chip_info adxl382_chip_info = { 200 + .name = "adxl382", 201 + .chip_id = ADXL382_ID_VAL, 202 + .scale_tbl = { 203 + [ADXL382_OP_MODE_15G_RANGE] = { 0, 4903325 }, 204 + [ADXL382_OP_MODE_30G_RANGE] = { 0, 9806650 }, 205 + [ADXL382_OP_MODE_60G_RANGE] = { 0, 19613300 }, 206 + }, 207 + .samp_freq_tbl = { 16000, 32000, 64000 }, 208 + /* 209 + * The datasheet defines an intercept of 570 LSB at 25 degC 210 + * and a sensitivity of 10.2 LSB/C. 211 + */ 212 + .temp_offset = 25 * 102 / 10 - 570, 213 + }; 214 + EXPORT_SYMBOL_NS_GPL(adxl382_chip_info, IIO_ADXL380); 215 + 216 + static const unsigned int adxl380_th_reg_high_addr[2] = { 217 + [ADXL380_ACTIVITY] = ADXL380_THRESH_ACT_H_REG, 218 + [ADXL380_INACTIVITY] = ADXL380_THRESH_INACT_H_REG, 219 + }; 220 + 221 + static const unsigned int adxl380_time_reg_high_addr[2] = { 222 + [ADXL380_ACTIVITY] = ADXL380_TIME_ACT_H_REG, 223 + [ADXL380_INACTIVITY] = ADXL380_TIME_INACT_H_REG, 224 + }; 225 + 226 + static const unsigned int adxl380_tap_time_reg[2] = { 227 + [ADXL380_TAP_TIME_LATENT] = ADXL380_TAP_LATENT_REG, 228 + [ADXL380_TAP_TIME_WINDOW] = ADXL380_TAP_WINDOW_REG, 229 + }; 230 + 231 + struct adxl380_state { 232 + struct regmap *regmap; 233 + struct device *dev; 234 + const struct adxl380_chip_info *chip_info; 235 + /* 236 + * Synchronize access to members of driver state, and ensure atomicity 237 + * of consecutive regmap operations. 238 + */ 239 + struct mutex lock; 240 + enum adxl380_axis tap_axis_en; 241 + u8 range; 242 + u8 odr; 243 + u8 fifo_set_size; 244 + u8 transf_buf[3]; 245 + u16 watermark; 246 + u32 act_time_ms; 247 + u32 act_threshold; 248 + u32 inact_time_ms; 249 + u32 inact_threshold; 250 + u32 tap_latent_us; 251 + u32 tap_window_us; 252 + u32 tap_duration_us; 253 + u32 tap_threshold; 254 + int irq; 255 + int int_map[2]; 256 + int lpf_tbl[4]; 257 + int hpf_tbl[7][2]; 258 + 259 + __be16 fifo_buf[ADXL380_FIFO_SAMPLES] __aligned(IIO_DMA_MINALIGN); 260 + }; 261 + 262 + bool adxl380_readable_noinc_reg(struct device *dev, unsigned int reg) 263 + { 264 + return reg == ADXL380_FIFO_DATA; 265 + } 266 + EXPORT_SYMBOL_NS_GPL(adxl380_readable_noinc_reg, IIO_ADXL380); 267 + 268 + static int adxl380_set_measure_en(struct adxl380_state *st, bool en) 269 + { 270 + int ret; 271 + unsigned int act_inact_ctl; 272 + u8 op_mode = ADXL380_OP_MODE_STANDBY; 273 + 274 + if (en) { 275 + ret = regmap_read(st->regmap, ADXL380_ACT_INACT_CTL_REG, &act_inact_ctl); 276 + if (ret) 277 + return ret; 278 + 279 + /* Activity/ Inactivity detection available only in VLP/ULP mode */ 280 + if (FIELD_GET(ADXL380_ACT_EN_MSK, act_inact_ctl) || 281 + FIELD_GET(ADXL380_INACT_EN_MSK, act_inact_ctl)) 282 + op_mode = ADXL380_OP_MODE_VLP; 283 + else 284 + op_mode = ADXL380_OP_MODE_HP; 285 + } 286 + 287 + return regmap_update_bits(st->regmap, ADXL380_OP_MODE_REG, 288 + ADXL380_OP_MODE_MSK, 289 + FIELD_PREP(ADXL380_OP_MODE_MSK, op_mode)); 290 + } 291 + 292 + static void adxl380_scale_act_inact_thresholds(struct adxl380_state *st, 293 + u8 old_range, 294 + u8 new_range) 295 + { 296 + st->act_threshold = mult_frac(st->act_threshold, 297 + adxl380_range_scale_factor_tbl[old_range], 298 + adxl380_range_scale_factor_tbl[new_range]); 299 + st->inact_threshold = mult_frac(st->inact_threshold, 300 + adxl380_range_scale_factor_tbl[old_range], 301 + adxl380_range_scale_factor_tbl[new_range]); 302 + } 303 + 304 + static int adxl380_write_act_inact_threshold(struct adxl380_state *st, 305 + enum adxl380_activity_type act, 306 + unsigned int th) 307 + { 308 + int ret; 309 + u8 reg = adxl380_th_reg_high_addr[act]; 310 + 311 + if (th > ADXL380_THRESH_MAX) 312 + return -EINVAL; 313 + 314 + ret = regmap_write(st->regmap, reg + 1, th & GENMASK(7, 0)); 315 + if (ret) 316 + return ret; 317 + 318 + ret = regmap_update_bits(st->regmap, reg, GENMASK(2, 0), th >> 8); 319 + if (ret) 320 + return ret; 321 + 322 + if (act == ADXL380_ACTIVITY) 323 + st->act_threshold = th; 324 + else 325 + st->inact_threshold = th; 326 + 327 + return 0; 328 + } 329 + 330 + static int adxl380_set_act_inact_threshold(struct iio_dev *indio_dev, 331 + enum adxl380_activity_type act, 332 + u16 th) 333 + { 334 + struct adxl380_state *st = iio_priv(indio_dev); 335 + int ret; 336 + 337 + guard(mutex)(&st->lock); 338 + 339 + ret = adxl380_set_measure_en(st, false); 340 + if (ret) 341 + return ret; 342 + 343 + ret = adxl380_write_act_inact_threshold(st, act, th); 344 + if (ret) 345 + return ret; 346 + 347 + return adxl380_set_measure_en(st, true); 348 + } 349 + 350 + static int adxl380_set_tap_threshold_value(struct iio_dev *indio_dev, u8 th) 351 + { 352 + int ret; 353 + struct adxl380_state *st = iio_priv(indio_dev); 354 + 355 + guard(mutex)(&st->lock); 356 + 357 + ret = adxl380_set_measure_en(st, false); 358 + if (ret) 359 + return ret; 360 + 361 + ret = regmap_write(st->regmap, ADXL380_TAP_THRESH_REG, th); 362 + if (ret) 363 + return ret; 364 + 365 + st->tap_threshold = th; 366 + 367 + return adxl380_set_measure_en(st, true); 368 + } 369 + 370 + static int _adxl380_write_tap_time_us(struct adxl380_state *st, 371 + enum adxl380_tap_time_type tap_time_type, 372 + u32 us) 373 + { 374 + u8 reg = adxl380_tap_time_reg[tap_time_type]; 375 + unsigned int reg_val; 376 + int ret; 377 + 378 + /* scale factor for tap window is 1250us / LSB */ 379 + reg_val = DIV_ROUND_CLOSEST(us, 1250); 380 + if (reg_val > ADXL380_TAP_TIME_MAX) 381 + reg_val = ADXL380_TAP_TIME_MAX; 382 + 383 + ret = regmap_write(st->regmap, reg, reg_val); 384 + if (ret) 385 + return ret; 386 + 387 + if (tap_time_type == ADXL380_TAP_TIME_WINDOW) 388 + st->tap_window_us = us; 389 + else 390 + st->tap_latent_us = us; 391 + 392 + return 0; 393 + } 394 + 395 + static int adxl380_write_tap_time_us(struct adxl380_state *st, 396 + enum adxl380_tap_time_type tap_time_type, u32 us) 397 + { 398 + int ret; 399 + 400 + guard(mutex)(&st->lock); 401 + 402 + ret = adxl380_set_measure_en(st, false); 403 + if (ret) 404 + return ret; 405 + 406 + ret = _adxl380_write_tap_time_us(st, tap_time_type, us); 407 + if (ret) 408 + return ret; 409 + 410 + return adxl380_set_measure_en(st, true); 411 + } 412 + 413 + static int adxl380_write_tap_dur_us(struct iio_dev *indio_dev, u32 us) 414 + { 415 + int ret; 416 + unsigned int reg_val; 417 + struct adxl380_state *st = iio_priv(indio_dev); 418 + 419 + /* 625us per code is the scale factor of TAP_DUR register */ 420 + reg_val = DIV_ROUND_CLOSEST(us, 625); 421 + 422 + ret = adxl380_set_measure_en(st, false); 423 + if (ret) 424 + return ret; 425 + 426 + ret = regmap_write(st->regmap, ADXL380_TAP_DUR_REG, reg_val); 427 + if (ret) 428 + return ret; 429 + 430 + return adxl380_set_measure_en(st, true); 431 + } 432 + 433 + static int adxl380_read_chn(struct adxl380_state *st, u8 addr) 434 + { 435 + int ret; 436 + 437 + guard(mutex)(&st->lock); 438 + 439 + ret = regmap_bulk_read(st->regmap, addr, &st->transf_buf, 2); 440 + if (ret) 441 + return ret; 442 + 443 + return get_unaligned_be16(st->transf_buf); 444 + } 445 + 446 + static int adxl380_get_odr(struct adxl380_state *st, int *odr) 447 + { 448 + int ret; 449 + unsigned int trig_cfg, odr_idx; 450 + 451 + ret = regmap_read(st->regmap, ADXL380_TRIG_CFG_REG, &trig_cfg); 452 + if (ret) 453 + return ret; 454 + 455 + odr_idx = (FIELD_GET(ADXL380_TRIG_CFG_SINC_RATE_MSK, trig_cfg) << 1) | 456 + (FIELD_GET(ADXL380_TRIG_CFG_DEC_2X_MSK, trig_cfg) & 1); 457 + 458 + *odr = st->chip_info->samp_freq_tbl[odr_idx]; 459 + 460 + return 0; 461 + } 462 + 463 + static const int adxl380_lpf_div[] = { 464 + 1, 4, 8, 16, 465 + }; 466 + 467 + static int adxl380_fill_lpf_tbl(struct adxl380_state *st) 468 + { 469 + int ret, i; 470 + int odr; 471 + 472 + ret = adxl380_get_odr(st, &odr); 473 + if (ret) 474 + return ret; 475 + 476 + for (i = 0; i < ARRAY_SIZE(st->lpf_tbl); i++) 477 + st->lpf_tbl[i] = DIV_ROUND_CLOSEST(odr, adxl380_lpf_div[i]); 478 + 479 + return 0; 480 + } 481 + 482 + static const int adxl380_hpf_mul[] = { 483 + 0, 247000, 62084, 15545, 3862, 954, 238, 484 + }; 485 + 486 + static int adxl380_fill_hpf_tbl(struct adxl380_state *st) 487 + { 488 + int i, ret, odr_hz; 489 + u32 multiplier; 490 + u64 div, rem, odr; 491 + 492 + ret = adxl380_get_odr(st, &odr_hz); 493 + if (ret) 494 + return ret; 495 + 496 + for (i = 0; i < ARRAY_SIZE(adxl380_hpf_mul); i++) { 497 + odr = mul_u64_u32_shr(odr_hz, MEGA, 0); 498 + multiplier = adxl380_hpf_mul[i]; 499 + div = div64_u64_rem(mul_u64_u32_shr(odr, multiplier, 0), 500 + TERA * 100, &rem); 501 + 502 + st->hpf_tbl[i][0] = div; 503 + st->hpf_tbl[i][1] = div_u64(rem, MEGA * 100); 504 + } 505 + 506 + return 0; 507 + } 508 + 509 + static int adxl380_set_odr(struct adxl380_state *st, u8 odr) 510 + { 511 + int ret; 512 + 513 + guard(mutex)(&st->lock); 514 + 515 + ret = adxl380_set_measure_en(st, false); 516 + if (ret) 517 + return ret; 518 + 519 + ret = regmap_update_bits(st->regmap, ADXL380_TRIG_CFG_REG, 520 + ADXL380_TRIG_CFG_DEC_2X_MSK, 521 + FIELD_PREP(ADXL380_TRIG_CFG_DEC_2X_MSK, odr & 1)); 522 + if (ret) 523 + return ret; 524 + 525 + ret = regmap_update_bits(st->regmap, ADXL380_TRIG_CFG_REG, 526 + ADXL380_TRIG_CFG_SINC_RATE_MSK, 527 + FIELD_PREP(ADXL380_TRIG_CFG_SINC_RATE_MSK, odr >> 1)); 528 + if (ret) 529 + return ret; 530 + 531 + ret = adxl380_set_measure_en(st, true); 532 + if (ret) 533 + return ret; 534 + 535 + ret = adxl380_fill_lpf_tbl(st); 536 + if (ret) 537 + return ret; 538 + 539 + return adxl380_fill_hpf_tbl(st); 540 + } 541 + 542 + static int adxl380_find_match_1d_tbl(const int *array, unsigned int size, 543 + int val) 544 + { 545 + int i; 546 + 547 + for (i = 0; i < size; i++) { 548 + if (val == array[i]) 549 + return i; 550 + } 551 + 552 + return size - 1; 553 + } 554 + 555 + static int adxl380_find_match_2d_tbl(const int (*freq_tbl)[2], int n, int val, int val2) 556 + { 557 + int i; 558 + 559 + for (i = 0; i < n; i++) { 560 + if (freq_tbl[i][0] == val && freq_tbl[i][1] == val2) 561 + return i; 562 + } 563 + 564 + return -EINVAL; 565 + } 566 + 567 + static int adxl380_get_lpf(struct adxl380_state *st, int *lpf) 568 + { 569 + int ret; 570 + unsigned int trig_cfg, lpf_idx; 571 + 572 + guard(mutex)(&st->lock); 573 + 574 + ret = regmap_read(st->regmap, ADXL380_FILTER_REG, &trig_cfg); 575 + if (ret) 576 + return ret; 577 + 578 + lpf_idx = FIELD_GET(ADXL380_FILTER_LPF_MODE_MSK, trig_cfg); 579 + 580 + *lpf = st->lpf_tbl[lpf_idx]; 581 + 582 + return 0; 583 + } 584 + 585 + static int adxl380_set_lpf(struct adxl380_state *st, u8 lpf) 586 + { 587 + int ret; 588 + u8 eq_bypass = 0; 589 + 590 + guard(mutex)(&st->lock); 591 + 592 + ret = adxl380_set_measure_en(st, false); 593 + if (ret) 594 + return ret; 595 + 596 + if (lpf) 597 + eq_bypass = 1; 598 + 599 + ret = regmap_update_bits(st->regmap, ADXL380_FILTER_REG, 600 + ADXL380_FILTER_EQ_FILT_MSK, 601 + FIELD_PREP(ADXL380_FILTER_EQ_FILT_MSK, eq_bypass)); 602 + if (ret) 603 + return ret; 604 + 605 + ret = regmap_update_bits(st->regmap, ADXL380_FILTER_REG, 606 + ADXL380_FILTER_LPF_MODE_MSK, 607 + FIELD_PREP(ADXL380_FILTER_LPF_MODE_MSK, lpf)); 608 + if (ret) 609 + return ret; 610 + 611 + return adxl380_set_measure_en(st, true); 612 + } 613 + 614 + static int adxl380_get_hpf(struct adxl380_state *st, int *hpf_int, int *hpf_frac) 615 + { 616 + int ret; 617 + unsigned int trig_cfg, hpf_idx; 618 + 619 + guard(mutex)(&st->lock); 620 + 621 + ret = regmap_read(st->regmap, ADXL380_FILTER_REG, &trig_cfg); 622 + if (ret) 623 + return ret; 624 + 625 + hpf_idx = FIELD_GET(ADXL380_FILTER_HPF_CORNER_MSK, trig_cfg); 626 + 627 + *hpf_int = st->hpf_tbl[hpf_idx][0]; 628 + *hpf_frac = st->hpf_tbl[hpf_idx][1]; 629 + 630 + return 0; 631 + } 632 + 633 + static int adxl380_set_hpf(struct adxl380_state *st, u8 hpf) 634 + { 635 + int ret; 636 + u8 hpf_path = 0; 637 + 638 + guard(mutex)(&st->lock); 639 + 640 + ret = adxl380_set_measure_en(st, false); 641 + if (ret) 642 + return ret; 643 + 644 + if (hpf) 645 + hpf_path = 1; 646 + 647 + ret = regmap_update_bits(st->regmap, ADXL380_FILTER_REG, 648 + ADXL380_FILTER_HPF_PATH_MSK, 649 + FIELD_PREP(ADXL380_FILTER_HPF_PATH_MSK, hpf_path)); 650 + if (ret) 651 + return ret; 652 + 653 + ret = regmap_update_bits(st->regmap, ADXL380_FILTER_REG, 654 + ADXL380_FILTER_HPF_CORNER_MSK, 655 + FIELD_PREP(ADXL380_FILTER_HPF_CORNER_MSK, hpf)); 656 + if (ret) 657 + return ret; 658 + 659 + return adxl380_set_measure_en(st, true); 660 + } 661 + 662 + static int _adxl380_set_act_inact_time_ms(struct adxl380_state *st, 663 + enum adxl380_activity_type act, 664 + u32 ms) 665 + { 666 + u8 reg = adxl380_time_reg_high_addr[act]; 667 + unsigned int reg_val; 668 + int ret; 669 + 670 + /* 500us per code is the scale factor of TIME_ACT / TIME_INACT registers */ 671 + reg_val = min(DIV_ROUND_CLOSEST(ms * 1000, 500), ADXL380_TIME_MAX); 672 + 673 + put_unaligned_be24(reg_val, &st->transf_buf[0]); 674 + 675 + ret = regmap_bulk_write(st->regmap, reg, st->transf_buf, sizeof(st->transf_buf)); 676 + if (ret) 677 + return ret; 678 + 679 + if (act == ADXL380_ACTIVITY) 680 + st->act_time_ms = ms; 681 + else 682 + st->inact_time_ms = ms; 683 + 684 + return 0; 685 + } 686 + 687 + static int adxl380_set_act_inact_time_ms(struct adxl380_state *st, 688 + enum adxl380_activity_type act, 689 + u32 ms) 690 + { 691 + int ret; 692 + 693 + guard(mutex)(&st->lock); 694 + 695 + ret = adxl380_set_measure_en(st, false); 696 + if (ret) 697 + return ret; 698 + 699 + ret = _adxl380_set_act_inact_time_ms(st, act, ms); 700 + if (ret) 701 + return ret; 702 + 703 + return adxl380_set_measure_en(st, true); 704 + } 705 + 706 + static int adxl380_set_range(struct adxl380_state *st, u8 range) 707 + { 708 + int ret; 709 + 710 + guard(mutex)(&st->lock); 711 + 712 + ret = adxl380_set_measure_en(st, false); 713 + if (ret) 714 + return ret; 715 + 716 + ret = regmap_update_bits(st->regmap, ADXL380_OP_MODE_REG, 717 + ADXL380_OP_MODE_RANGE_MSK, 718 + FIELD_PREP(ADXL380_OP_MODE_RANGE_MSK, range)); 719 + 720 + if (ret) 721 + return ret; 722 + 723 + adxl380_scale_act_inact_thresholds(st, st->range, range); 724 + 725 + /* Activity thresholds depend on range */ 726 + ret = adxl380_write_act_inact_threshold(st, ADXL380_ACTIVITY, 727 + st->act_threshold); 728 + if (ret) 729 + return ret; 730 + 731 + ret = adxl380_write_act_inact_threshold(st, ADXL380_INACTIVITY, 732 + st->inact_threshold); 733 + if (ret) 734 + return ret; 735 + 736 + st->range = range; 737 + 738 + return adxl380_set_measure_en(st, true); 739 + } 740 + 741 + static int adxl380_write_act_inact_en(struct adxl380_state *st, 742 + enum adxl380_activity_type type, 743 + bool en) 744 + { 745 + if (type == ADXL380_ACTIVITY) 746 + return regmap_update_bits(st->regmap, ADXL380_ACT_INACT_CTL_REG, 747 + ADXL380_ACT_EN_MSK, 748 + FIELD_PREP(ADXL380_ACT_EN_MSK, en)); 749 + 750 + return regmap_update_bits(st->regmap, ADXL380_ACT_INACT_CTL_REG, 751 + ADXL380_INACT_EN_MSK, 752 + FIELD_PREP(ADXL380_INACT_EN_MSK, en)); 753 + } 754 + 755 + static int adxl380_read_act_inact_int(struct adxl380_state *st, 756 + enum adxl380_activity_type type, 757 + bool *en) 758 + { 759 + int ret; 760 + unsigned int reg_val; 761 + 762 + guard(mutex)(&st->lock); 763 + 764 + ret = regmap_read(st->regmap, st->int_map[0], &reg_val); 765 + if (ret) 766 + return ret; 767 + 768 + if (type == ADXL380_ACTIVITY) 769 + *en = FIELD_GET(ADXL380_INT_MAP0_ACT_INT0_MSK, reg_val); 770 + else 771 + *en = FIELD_GET(ADXL380_INT_MAP0_INACT_INT0_MSK, reg_val); 772 + 773 + return 0; 774 + } 775 + 776 + static int adxl380_write_act_inact_int(struct adxl380_state *st, 777 + enum adxl380_activity_type act, 778 + bool en) 779 + { 780 + if (act == ADXL380_ACTIVITY) 781 + return regmap_update_bits(st->regmap, st->int_map[0], 782 + ADXL380_INT_MAP0_ACT_INT0_MSK, 783 + FIELD_PREP(ADXL380_INT_MAP0_ACT_INT0_MSK, en)); 784 + 785 + return regmap_update_bits(st->regmap, st->int_map[0], 786 + ADXL380_INT_MAP0_INACT_INT0_MSK, 787 + FIELD_PREP(ADXL380_INT_MAP0_INACT_INT0_MSK, en)); 788 + } 789 + 790 + static int adxl380_act_inact_config(struct adxl380_state *st, 791 + enum adxl380_activity_type type, 792 + bool en) 793 + { 794 + int ret; 795 + 796 + guard(mutex)(&st->lock); 797 + 798 + ret = adxl380_set_measure_en(st, false); 799 + if (ret) 800 + return ret; 801 + 802 + ret = adxl380_write_act_inact_en(st, type, en); 803 + if (ret) 804 + return ret; 805 + 806 + ret = adxl380_write_act_inact_int(st, type, en); 807 + if (ret) 808 + return ret; 809 + 810 + return adxl380_set_measure_en(st, true); 811 + } 812 + 813 + static int adxl380_write_tap_axis(struct adxl380_state *st, 814 + enum adxl380_axis axis) 815 + { 816 + int ret; 817 + 818 + ret = regmap_update_bits(st->regmap, ADXL380_TAP_CFG_REG, 819 + ADXL380_TAP_AXIS_MSK, 820 + FIELD_PREP(ADXL380_TAP_AXIS_MSK, axis)); 821 + 822 + if (ret) 823 + return ret; 824 + 825 + st->tap_axis_en = axis; 826 + 827 + return 0; 828 + } 829 + 830 + static int adxl380_read_tap_int(struct adxl380_state *st, enum adxl380_tap_type type, bool *en) 831 + { 832 + int ret; 833 + unsigned int reg_val; 834 + 835 + ret = regmap_read(st->regmap, st->int_map[1], &reg_val); 836 + if (ret) 837 + return ret; 838 + 839 + if (type == ADXL380_SINGLE_TAP) 840 + *en = FIELD_GET(ADXL380_INT_MAP1_SINGLE_TAP_INT0_MSK, reg_val); 841 + else 842 + *en = FIELD_GET(ADXL380_INT_MAP1_DOUBLE_TAP_INT0_MSK, reg_val); 843 + 844 + return 0; 845 + } 846 + 847 + static int adxl380_write_tap_int(struct adxl380_state *st, enum adxl380_tap_type type, bool en) 848 + { 849 + if (type == ADXL380_SINGLE_TAP) 850 + return regmap_update_bits(st->regmap, st->int_map[1], 851 + ADXL380_INT_MAP1_SINGLE_TAP_INT0_MSK, 852 + FIELD_PREP(ADXL380_INT_MAP1_SINGLE_TAP_INT0_MSK, en)); 853 + 854 + return regmap_update_bits(st->regmap, st->int_map[1], 855 + ADXL380_INT_MAP1_DOUBLE_TAP_INT0_MSK, 856 + FIELD_PREP(ADXL380_INT_MAP1_DOUBLE_TAP_INT0_MSK, en)); 857 + } 858 + 859 + static int adxl380_tap_config(struct adxl380_state *st, 860 + enum adxl380_axis axis, 861 + enum adxl380_tap_type type, 862 + bool en) 863 + { 864 + int ret; 865 + 866 + guard(mutex)(&st->lock); 867 + 868 + ret = adxl380_set_measure_en(st, false); 869 + if (ret) 870 + return ret; 871 + 872 + ret = adxl380_write_tap_axis(st, axis); 873 + if (ret) 874 + return ret; 875 + 876 + ret = adxl380_write_tap_int(st, type, en); 877 + if (ret) 878 + return ret; 879 + 880 + return adxl380_set_measure_en(st, true); 881 + } 882 + 883 + static int adxl380_set_fifo_samples(struct adxl380_state *st) 884 + { 885 + int ret; 886 + u16 fifo_samples = st->watermark * st->fifo_set_size; 887 + 888 + ret = regmap_update_bits(st->regmap, ADXL380_FIFO_CONFIG_0_REG, 889 + ADXL380_FIFO_SAMPLES_8_MSK, 890 + FIELD_PREP(ADXL380_FIFO_SAMPLES_8_MSK, 891 + (fifo_samples & BIT(8)))); 892 + if (ret) 893 + return ret; 894 + 895 + return regmap_write(st->regmap, ADXL380_FIFO_CONFIG_1_REG, 896 + fifo_samples & 0xFF); 897 + } 898 + 899 + static int adxl380_get_status(struct adxl380_state *st, u8 *status0, u8 *status1) 900 + { 901 + int ret; 902 + 903 + /* STATUS0, STATUS1 are adjacent regs */ 904 + ret = regmap_bulk_read(st->regmap, ADXL380_STATUS_0_REG, 905 + &st->transf_buf, 2); 906 + if (ret) 907 + return ret; 908 + 909 + *status0 = st->transf_buf[0]; 910 + *status1 = st->transf_buf[1]; 911 + 912 + return 0; 913 + } 914 + 915 + static int adxl380_get_fifo_entries(struct adxl380_state *st, u16 *fifo_entries) 916 + { 917 + int ret; 918 + 919 + ret = regmap_bulk_read(st->regmap, ADXL380_FIFO_STATUS_0_REG, 920 + &st->transf_buf, 2); 921 + if (ret) 922 + return ret; 923 + 924 + *fifo_entries = st->transf_buf[0] | ((BIT(0) & st->transf_buf[1]) << 8); 925 + 926 + return 0; 927 + } 928 + 929 + static void adxl380_push_event(struct iio_dev *indio_dev, s64 timestamp, 930 + u8 status1) 931 + { 932 + if (FIELD_GET(ADXL380_STATUS_1_ACT_MSK, status1)) 933 + iio_push_event(indio_dev, 934 + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, 935 + IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), 936 + timestamp); 937 + 938 + if (FIELD_GET(ADXL380_STATUS_1_INACT_MSK, status1)) 939 + iio_push_event(indio_dev, 940 + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, 941 + IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), 942 + timestamp); 943 + if (FIELD_GET(ADXL380_STATUS_1_SINGLE_TAP_MSK, status1)) 944 + iio_push_event(indio_dev, 945 + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, 946 + IIO_EV_TYPE_GESTURE, IIO_EV_DIR_SINGLETAP), 947 + timestamp); 948 + 949 + if (FIELD_GET(ADXL380_STATUS_1_DOUBLE_TAP_MSK, status1)) 950 + iio_push_event(indio_dev, 951 + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, 952 + IIO_EV_TYPE_GESTURE, IIO_EV_DIR_DOUBLETAP), 953 + timestamp); 954 + } 955 + 956 + static irqreturn_t adxl380_irq_handler(int irq, void *p) 957 + { 958 + struct iio_dev *indio_dev = p; 959 + struct adxl380_state *st = iio_priv(indio_dev); 960 + u8 status0, status1; 961 + u16 fifo_entries; 962 + int i; 963 + int ret; 964 + 965 + guard(mutex)(&st->lock); 966 + 967 + ret = adxl380_get_status(st, &status0, &status1); 968 + if (ret) 969 + return IRQ_HANDLED; 970 + 971 + adxl380_push_event(indio_dev, iio_get_time_ns(indio_dev), status1); 972 + 973 + if (!FIELD_GET(ADXL380_STATUS_0_FIFO_WM_MSK, status0)) 974 + return IRQ_HANDLED; 975 + 976 + ret = adxl380_get_fifo_entries(st, &fifo_entries); 977 + if (ret) 978 + return IRQ_HANDLED; 979 + 980 + for (i = 0; i < fifo_entries; i += st->fifo_set_size) { 981 + ret = regmap_noinc_read(st->regmap, ADXL380_FIFO_DATA, 982 + &st->fifo_buf[i], 983 + 2 * st->fifo_set_size); 984 + if (ret) 985 + return IRQ_HANDLED; 986 + iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); 987 + } 988 + 989 + return IRQ_HANDLED; 990 + } 991 + 992 + static int adxl380_write_calibbias_value(struct adxl380_state *st, 993 + unsigned long chan_addr, 994 + s8 calibbias) 995 + { 996 + int ret; 997 + 998 + guard(mutex)(&st->lock); 999 + 1000 + ret = adxl380_set_measure_en(st, false); 1001 + if (ret) 1002 + return ret; 1003 + 1004 + ret = regmap_write(st->regmap, ADXL380_X_DSM_OFFSET_REG + chan_addr, calibbias); 1005 + if (ret) 1006 + return ret; 1007 + 1008 + return adxl380_set_measure_en(st, true); 1009 + } 1010 + 1011 + static int adxl380_read_calibbias_value(struct adxl380_state *st, 1012 + unsigned long chan_addr, 1013 + int *calibbias) 1014 + { 1015 + int ret; 1016 + unsigned int reg_val; 1017 + 1018 + guard(mutex)(&st->lock); 1019 + 1020 + ret = regmap_read(st->regmap, ADXL380_X_DSM_OFFSET_REG + chan_addr, &reg_val); 1021 + if (ret) 1022 + return ret; 1023 + 1024 + *calibbias = sign_extend32(reg_val, 7); 1025 + 1026 + return 0; 1027 + } 1028 + 1029 + static ssize_t hwfifo_watermark_min_show(struct device *dev, 1030 + struct device_attribute *attr, 1031 + char *buf) 1032 + { 1033 + return sysfs_emit(buf, "1\n"); 1034 + } 1035 + 1036 + static ssize_t hwfifo_watermark_max_show(struct device *dev, 1037 + struct device_attribute *attr, 1038 + char *buf) 1039 + { 1040 + return sysfs_emit(buf, "%lu\n", ADXL380_FIFO_SAMPLES); 1041 + } 1042 + 1043 + static ssize_t adxl380_get_fifo_watermark(struct device *dev, 1044 + struct device_attribute *attr, 1045 + char *buf) 1046 + { 1047 + struct iio_dev *indio_dev = dev_to_iio_dev(dev); 1048 + struct adxl380_state *st = iio_priv(indio_dev); 1049 + 1050 + return sysfs_emit(buf, "%d\n", st->watermark); 1051 + } 1052 + 1053 + static ssize_t adxl380_get_fifo_enabled(struct device *dev, 1054 + struct device_attribute *attr, 1055 + char *buf) 1056 + { 1057 + struct iio_dev *indio_dev = dev_to_iio_dev(dev); 1058 + struct adxl380_state *st = iio_priv(indio_dev); 1059 + int ret; 1060 + unsigned int reg_val; 1061 + 1062 + ret = regmap_read(st->regmap, ADXL380_DIG_EN_REG, &reg_val); 1063 + if (ret) 1064 + return ret; 1065 + 1066 + return sysfs_emit(buf, "%lu\n", 1067 + FIELD_GET(ADXL380_FIFO_EN_MSK, reg_val)); 1068 + } 1069 + 1070 + static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0); 1071 + static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0); 1072 + static IIO_DEVICE_ATTR(hwfifo_watermark, 0444, 1073 + adxl380_get_fifo_watermark, NULL, 0); 1074 + static IIO_DEVICE_ATTR(hwfifo_enabled, 0444, 1075 + adxl380_get_fifo_enabled, NULL, 0); 1076 + 1077 + static const struct iio_dev_attr *adxl380_fifo_attributes[] = { 1078 + &iio_dev_attr_hwfifo_watermark_min, 1079 + &iio_dev_attr_hwfifo_watermark_max, 1080 + &iio_dev_attr_hwfifo_watermark, 1081 + &iio_dev_attr_hwfifo_enabled, 1082 + NULL 1083 + }; 1084 + 1085 + static int adxl380_buffer_postenable(struct iio_dev *indio_dev) 1086 + { 1087 + struct adxl380_state *st = iio_priv(indio_dev); 1088 + int i; 1089 + int ret; 1090 + 1091 + guard(mutex)(&st->lock); 1092 + 1093 + ret = adxl380_set_measure_en(st, false); 1094 + if (ret) 1095 + return ret; 1096 + 1097 + ret = regmap_update_bits(st->regmap, 1098 + st->int_map[0], 1099 + ADXL380_INT_MAP0_FIFO_WM_INT0_MSK, 1100 + FIELD_PREP(ADXL380_INT_MAP0_FIFO_WM_INT0_MSK, 1)); 1101 + if (ret) 1102 + return ret; 1103 + 1104 + for_each_clear_bit(i, indio_dev->active_scan_mask, ADXL380_CH_NUM) { 1105 + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, 1106 + ADXL380_CHAN_EN_MSK(i), 1107 + 0 << (4 + i)); 1108 + if (ret) 1109 + return ret; 1110 + } 1111 + 1112 + st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask, 1113 + indio_dev->masklength); 1114 + 1115 + if ((st->watermark * st->fifo_set_size) > ADXL380_FIFO_SAMPLES) 1116 + st->watermark = (ADXL380_FIFO_SAMPLES / st->fifo_set_size); 1117 + 1118 + ret = adxl380_set_fifo_samples(st); 1119 + if (ret) 1120 + return ret; 1121 + 1122 + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, ADXL380_FIFO_EN_MSK, 1123 + FIELD_PREP(ADXL380_FIFO_EN_MSK, 1)); 1124 + if (ret) 1125 + return ret; 1126 + 1127 + return adxl380_set_measure_en(st, true); 1128 + } 1129 + 1130 + static int adxl380_buffer_predisable(struct iio_dev *indio_dev) 1131 + { 1132 + struct adxl380_state *st = iio_priv(indio_dev); 1133 + int ret, i; 1134 + 1135 + guard(mutex)(&st->lock); 1136 + 1137 + ret = adxl380_set_measure_en(st, false); 1138 + if (ret) 1139 + return ret; 1140 + 1141 + ret = regmap_update_bits(st->regmap, 1142 + st->int_map[0], 1143 + ADXL380_INT_MAP0_FIFO_WM_INT0_MSK, 1144 + FIELD_PREP(ADXL380_INT_MAP0_FIFO_WM_INT0_MSK, 0)); 1145 + if (ret) 1146 + return ret; 1147 + 1148 + for (i = 0; i < indio_dev->num_channels; i++) { 1149 + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, 1150 + ADXL380_CHAN_EN_MSK(i), 1151 + 1 << (4 + i)); 1152 + if (ret) 1153 + return ret; 1154 + } 1155 + 1156 + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, ADXL380_FIFO_EN_MSK, 1157 + FIELD_PREP(ADXL380_FIFO_EN_MSK, 0)); 1158 + if (ret) 1159 + return ret; 1160 + 1161 + return adxl380_set_measure_en(st, true); 1162 + } 1163 + 1164 + static const struct iio_buffer_setup_ops adxl380_buffer_ops = { 1165 + .postenable = adxl380_buffer_postenable, 1166 + .predisable = adxl380_buffer_predisable, 1167 + }; 1168 + 1169 + static int adxl380_read_raw(struct iio_dev *indio_dev, 1170 + struct iio_chan_spec const *chan, 1171 + int *val, int *val2, long info) 1172 + { 1173 + struct adxl380_state *st = iio_priv(indio_dev); 1174 + int ret; 1175 + 1176 + switch (info) { 1177 + case IIO_CHAN_INFO_RAW: 1178 + ret = iio_device_claim_direct_mode(indio_dev); 1179 + if (ret) 1180 + return ret; 1181 + 1182 + ret = adxl380_read_chn(st, chan->address); 1183 + iio_device_release_direct_mode(indio_dev); 1184 + if (ret) 1185 + return ret; 1186 + 1187 + *val = sign_extend32(ret >> chan->scan_type.shift, 1188 + chan->scan_type.realbits - 1); 1189 + return IIO_VAL_INT; 1190 + case IIO_CHAN_INFO_SCALE: 1191 + switch (chan->type) { 1192 + case IIO_ACCEL: 1193 + scoped_guard(mutex, &st->lock) { 1194 + *val = st->chip_info->scale_tbl[st->range][0]; 1195 + *val2 = st->chip_info->scale_tbl[st->range][1]; 1196 + } 1197 + return IIO_VAL_INT_PLUS_NANO; 1198 + case IIO_TEMP: 1199 + /* 10.2 LSB / Degree Celsius */ 1200 + *val = 10000; 1201 + *val2 = 102; 1202 + return IIO_VAL_FRACTIONAL; 1203 + default: 1204 + return -EINVAL; 1205 + } 1206 + case IIO_CHAN_INFO_OFFSET: 1207 + switch (chan->type) { 1208 + case IIO_TEMP: 1209 + *val = st->chip_info->temp_offset; 1210 + return IIO_VAL_INT; 1211 + default: 1212 + return -EINVAL; 1213 + } 1214 + case IIO_CHAN_INFO_CALIBBIAS: 1215 + switch (chan->type) { 1216 + case IIO_ACCEL: 1217 + ret = adxl380_read_calibbias_value(st, chan->scan_index, val); 1218 + if (ret) 1219 + return ret; 1220 + return IIO_VAL_INT; 1221 + default: 1222 + return -EINVAL; 1223 + } 1224 + case IIO_CHAN_INFO_SAMP_FREQ: 1225 + ret = adxl380_get_odr(st, val); 1226 + if (ret) 1227 + return ret; 1228 + return IIO_VAL_INT; 1229 + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 1230 + ret = adxl380_get_lpf(st, val); 1231 + if (ret) 1232 + return ret; 1233 + return IIO_VAL_INT; 1234 + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 1235 + ret = adxl380_get_hpf(st, val, val2); 1236 + if (ret) 1237 + return ret; 1238 + return IIO_VAL_INT_PLUS_MICRO; 1239 + } 1240 + 1241 + return -EINVAL; 1242 + } 1243 + 1244 + static int adxl380_read_avail(struct iio_dev *indio_dev, 1245 + struct iio_chan_spec const *chan, 1246 + const int **vals, int *type, int *length, 1247 + long mask) 1248 + { 1249 + struct adxl380_state *st = iio_priv(indio_dev); 1250 + 1251 + if (chan->type != IIO_ACCEL) 1252 + return -EINVAL; 1253 + 1254 + switch (mask) { 1255 + case IIO_CHAN_INFO_SCALE: 1256 + *vals = (const int *)st->chip_info->scale_tbl; 1257 + *type = IIO_VAL_INT_PLUS_NANO; 1258 + *length = ARRAY_SIZE(st->chip_info->scale_tbl) * 2; 1259 + return IIO_AVAIL_LIST; 1260 + case IIO_CHAN_INFO_SAMP_FREQ: 1261 + *vals = (const int *)st->chip_info->samp_freq_tbl; 1262 + *type = IIO_VAL_INT; 1263 + *length = ARRAY_SIZE(st->chip_info->samp_freq_tbl); 1264 + return IIO_AVAIL_LIST; 1265 + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 1266 + *vals = (const int *)st->lpf_tbl; 1267 + *type = IIO_VAL_INT; 1268 + *length = ARRAY_SIZE(st->lpf_tbl); 1269 + return IIO_AVAIL_LIST; 1270 + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 1271 + *vals = (const int *)st->hpf_tbl; 1272 + *type = IIO_VAL_INT_PLUS_MICRO; 1273 + /* Values are stored in a 2D matrix */ 1274 + *length = ARRAY_SIZE(st->hpf_tbl) * 2; 1275 + return IIO_AVAIL_LIST; 1276 + default: 1277 + return -EINVAL; 1278 + } 1279 + } 1280 + 1281 + static int adxl380_write_raw(struct iio_dev *indio_dev, 1282 + struct iio_chan_spec const *chan, 1283 + int val, int val2, long info) 1284 + { 1285 + struct adxl380_state *st = iio_priv(indio_dev); 1286 + int odr_index, lpf_index, hpf_index, range_index; 1287 + 1288 + switch (info) { 1289 + case IIO_CHAN_INFO_SAMP_FREQ: 1290 + odr_index = adxl380_find_match_1d_tbl(st->chip_info->samp_freq_tbl, 1291 + ARRAY_SIZE(st->chip_info->samp_freq_tbl), 1292 + val); 1293 + return adxl380_set_odr(st, odr_index); 1294 + case IIO_CHAN_INFO_CALIBBIAS: 1295 + return adxl380_write_calibbias_value(st, chan->scan_index, val); 1296 + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 1297 + lpf_index = adxl380_find_match_1d_tbl(st->lpf_tbl, 1298 + ARRAY_SIZE(st->lpf_tbl), 1299 + val); 1300 + return adxl380_set_lpf(st, lpf_index); 1301 + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 1302 + hpf_index = adxl380_find_match_2d_tbl(st->hpf_tbl, 1303 + ARRAY_SIZE(st->hpf_tbl), 1304 + val, val2); 1305 + if (hpf_index < 0) 1306 + return hpf_index; 1307 + return adxl380_set_hpf(st, hpf_index); 1308 + case IIO_CHAN_INFO_SCALE: 1309 + range_index = adxl380_find_match_2d_tbl(st->chip_info->scale_tbl, 1310 + ARRAY_SIZE(st->chip_info->scale_tbl), 1311 + val, val2); 1312 + if (range_index < 0) 1313 + return range_index; 1314 + return adxl380_set_range(st, range_index); 1315 + default: 1316 + return -EINVAL; 1317 + } 1318 + } 1319 + 1320 + static int adxl380_write_raw_get_fmt(struct iio_dev *indio_dev, 1321 + struct iio_chan_spec const *chan, 1322 + long info) 1323 + { 1324 + switch (info) { 1325 + case IIO_CHAN_INFO_SCALE: 1326 + if (chan->type != IIO_ACCEL) 1327 + return -EINVAL; 1328 + 1329 + return IIO_VAL_INT_PLUS_NANO; 1330 + default: 1331 + return IIO_VAL_INT_PLUS_MICRO; 1332 + } 1333 + } 1334 + 1335 + static int adxl380_read_event_config(struct iio_dev *indio_dev, 1336 + const struct iio_chan_spec *chan, 1337 + enum iio_event_type type, 1338 + enum iio_event_direction dir) 1339 + { 1340 + struct adxl380_state *st = iio_priv(indio_dev); 1341 + int ret; 1342 + bool int_en; 1343 + bool tap_axis_en = false; 1344 + 1345 + switch (chan->channel2) { 1346 + case IIO_MOD_X: 1347 + tap_axis_en = st->tap_axis_en == ADXL380_X_AXIS; 1348 + break; 1349 + case IIO_MOD_Y: 1350 + tap_axis_en = st->tap_axis_en == ADXL380_Y_AXIS; 1351 + break; 1352 + case IIO_MOD_Z: 1353 + tap_axis_en = st->tap_axis_en == ADXL380_Z_AXIS; 1354 + break; 1355 + default: 1356 + return -EINVAL; 1357 + } 1358 + 1359 + switch (dir) { 1360 + case IIO_EV_DIR_RISING: 1361 + ret = adxl380_read_act_inact_int(st, ADXL380_ACTIVITY, &int_en); 1362 + if (ret) 1363 + return ret; 1364 + return int_en; 1365 + case IIO_EV_DIR_FALLING: 1366 + ret = adxl380_read_act_inact_int(st, ADXL380_INACTIVITY, &int_en); 1367 + if (ret) 1368 + return ret; 1369 + return int_en; 1370 + case IIO_EV_DIR_SINGLETAP: 1371 + ret = adxl380_read_tap_int(st, ADXL380_SINGLE_TAP, &int_en); 1372 + if (ret) 1373 + return ret; 1374 + return int_en && tap_axis_en; 1375 + case IIO_EV_DIR_DOUBLETAP: 1376 + ret = adxl380_read_tap_int(st, ADXL380_DOUBLE_TAP, &int_en); 1377 + if (ret) 1378 + return ret; 1379 + return int_en && tap_axis_en; 1380 + default: 1381 + return -EINVAL; 1382 + } 1383 + } 1384 + 1385 + static int adxl380_write_event_config(struct iio_dev *indio_dev, 1386 + const struct iio_chan_spec *chan, 1387 + enum iio_event_type type, 1388 + enum iio_event_direction dir, 1389 + int state) 1390 + { 1391 + struct adxl380_state *st = iio_priv(indio_dev); 1392 + enum adxl380_axis axis; 1393 + 1394 + switch (chan->channel2) { 1395 + case IIO_MOD_X: 1396 + axis = ADXL380_X_AXIS; 1397 + break; 1398 + case IIO_MOD_Y: 1399 + axis = ADXL380_Y_AXIS; 1400 + break; 1401 + case IIO_MOD_Z: 1402 + axis = ADXL380_Z_AXIS; 1403 + break; 1404 + default: 1405 + return -EINVAL; 1406 + } 1407 + 1408 + switch (dir) { 1409 + case IIO_EV_DIR_RISING: 1410 + return adxl380_act_inact_config(st, ADXL380_ACTIVITY, state); 1411 + case IIO_EV_DIR_FALLING: 1412 + return adxl380_act_inact_config(st, ADXL380_INACTIVITY, state); 1413 + case IIO_EV_DIR_SINGLETAP: 1414 + return adxl380_tap_config(st, axis, ADXL380_SINGLE_TAP, state); 1415 + case IIO_EV_DIR_DOUBLETAP: 1416 + return adxl380_tap_config(st, axis, ADXL380_DOUBLE_TAP, state); 1417 + default: 1418 + return -EINVAL; 1419 + } 1420 + } 1421 + 1422 + static int adxl380_read_event_value(struct iio_dev *indio_dev, 1423 + const struct iio_chan_spec *chan, 1424 + enum iio_event_type type, 1425 + enum iio_event_direction dir, 1426 + enum iio_event_info info, 1427 + int *val, int *val2) 1428 + { 1429 + struct adxl380_state *st = iio_priv(indio_dev); 1430 + 1431 + guard(mutex)(&st->lock); 1432 + 1433 + switch (type) { 1434 + case IIO_EV_TYPE_THRESH: 1435 + switch (info) { 1436 + case IIO_EV_INFO_VALUE: { 1437 + switch (dir) { 1438 + case IIO_EV_DIR_RISING: 1439 + *val = st->act_threshold; 1440 + return IIO_VAL_INT; 1441 + case IIO_EV_DIR_FALLING: 1442 + *val = st->inact_threshold; 1443 + return IIO_VAL_INT; 1444 + default: 1445 + return -EINVAL; 1446 + } 1447 + } 1448 + case IIO_EV_INFO_PERIOD: 1449 + switch (dir) { 1450 + case IIO_EV_DIR_RISING: 1451 + *val = st->act_time_ms; 1452 + *val2 = 1000; 1453 + return IIO_VAL_FRACTIONAL; 1454 + case IIO_EV_DIR_FALLING: 1455 + *val = st->inact_time_ms; 1456 + *val2 = 1000; 1457 + return IIO_VAL_FRACTIONAL; 1458 + default: 1459 + return -EINVAL; 1460 + } 1461 + default: 1462 + return -EINVAL; 1463 + } 1464 + case IIO_EV_TYPE_GESTURE: 1465 + switch (info) { 1466 + case IIO_EV_INFO_VALUE: 1467 + *val = st->tap_threshold; 1468 + return IIO_VAL_INT; 1469 + case IIO_EV_INFO_RESET_TIMEOUT: 1470 + *val = st->tap_window_us; 1471 + *val2 = 1000000; 1472 + return IIO_VAL_FRACTIONAL; 1473 + case IIO_EV_INFO_TAP2_MIN_DELAY: 1474 + *val = st->tap_latent_us; 1475 + *val2 = 1000000; 1476 + return IIO_VAL_FRACTIONAL; 1477 + default: 1478 + return -EINVAL; 1479 + } 1480 + default: 1481 + return -EINVAL; 1482 + } 1483 + } 1484 + 1485 + static int adxl380_write_event_value(struct iio_dev *indio_dev, 1486 + const struct iio_chan_spec *chan, 1487 + enum iio_event_type type, enum iio_event_direction dir, 1488 + enum iio_event_info info, int val, int val2) 1489 + { 1490 + struct adxl380_state *st = iio_priv(indio_dev); 1491 + u32 val_ms, val_us; 1492 + 1493 + if (chan->type != IIO_ACCEL) 1494 + return -EINVAL; 1495 + 1496 + switch (type) { 1497 + case IIO_EV_TYPE_THRESH: 1498 + switch (info) { 1499 + case IIO_EV_INFO_VALUE: 1500 + switch (dir) { 1501 + case IIO_EV_DIR_RISING: 1502 + return adxl380_set_act_inact_threshold(indio_dev, 1503 + ADXL380_ACTIVITY, val); 1504 + case IIO_EV_DIR_FALLING: 1505 + return adxl380_set_act_inact_threshold(indio_dev, 1506 + ADXL380_INACTIVITY, val); 1507 + default: 1508 + return -EINVAL; 1509 + } 1510 + case IIO_EV_INFO_PERIOD: 1511 + val_ms = val * 1000 + DIV_ROUND_UP(val2, 1000); 1512 + switch (dir) { 1513 + case IIO_EV_DIR_RISING: 1514 + return adxl380_set_act_inact_time_ms(st, 1515 + ADXL380_ACTIVITY, val_ms); 1516 + case IIO_EV_DIR_FALLING: 1517 + return adxl380_set_act_inact_time_ms(st, 1518 + ADXL380_INACTIVITY, val_ms); 1519 + default: 1520 + return -EINVAL; 1521 + } 1522 + 1523 + default: 1524 + return -EINVAL; 1525 + } 1526 + case IIO_EV_TYPE_GESTURE: 1527 + switch (info) { 1528 + case IIO_EV_INFO_VALUE: 1529 + return adxl380_set_tap_threshold_value(indio_dev, val); 1530 + case IIO_EV_INFO_RESET_TIMEOUT: 1531 + val_us = val * 1000000 + val2; 1532 + return adxl380_write_tap_time_us(st, 1533 + ADXL380_TAP_TIME_WINDOW, 1534 + val_us); 1535 + case IIO_EV_INFO_TAP2_MIN_DELAY: 1536 + val_us = val * 1000000 + val2; 1537 + return adxl380_write_tap_time_us(st, 1538 + ADXL380_TAP_TIME_LATENT, 1539 + val_us); 1540 + default: 1541 + return -EINVAL; 1542 + } 1543 + default: 1544 + return -EINVAL; 1545 + } 1546 + } 1547 + 1548 + static ssize_t in_accel_gesture_tap_maxtomin_time_show(struct device *dev, 1549 + struct device_attribute *attr, 1550 + char *buf) 1551 + { 1552 + int vals[2]; 1553 + struct iio_dev *indio_dev = dev_to_iio_dev(dev); 1554 + struct adxl380_state *st = iio_priv(indio_dev); 1555 + 1556 + guard(mutex)(&st->lock); 1557 + 1558 + vals[0] = st->tap_duration_us; 1559 + vals[1] = MICRO; 1560 + 1561 + return iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, vals); 1562 + } 1563 + 1564 + static ssize_t in_accel_gesture_tap_maxtomin_time_store(struct device *dev, 1565 + struct device_attribute *attr, 1566 + const char *buf, size_t len) 1567 + { 1568 + struct iio_dev *indio_dev = dev_to_iio_dev(dev); 1569 + struct adxl380_state *st = iio_priv(indio_dev); 1570 + int ret, val_int, val_fract_us; 1571 + 1572 + guard(mutex)(&st->lock); 1573 + 1574 + ret = iio_str_to_fixpoint(buf, 100000, &val_int, &val_fract_us); 1575 + if (ret) 1576 + return ret; 1577 + 1578 + /* maximum value is 255 * 625 us = 0.159375 seconds */ 1579 + if (val_int || val_fract_us > 159375 || val_fract_us < 0) 1580 + return -EINVAL; 1581 + 1582 + ret = adxl380_write_tap_dur_us(indio_dev, val_fract_us); 1583 + if (ret) 1584 + return ret; 1585 + 1586 + return len; 1587 + } 1588 + 1589 + static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_maxtomin_time, 0); 1590 + 1591 + static struct attribute *adxl380_event_attributes[] = { 1592 + &iio_dev_attr_in_accel_gesture_tap_maxtomin_time.dev_attr.attr, 1593 + NULL 1594 + }; 1595 + 1596 + static const struct attribute_group adxl380_event_attribute_group = { 1597 + .attrs = adxl380_event_attributes, 1598 + }; 1599 + 1600 + static int adxl380_reg_access(struct iio_dev *indio_dev, 1601 + unsigned int reg, 1602 + unsigned int writeval, 1603 + unsigned int *readval) 1604 + { 1605 + struct adxl380_state *st = iio_priv(indio_dev); 1606 + 1607 + if (readval) 1608 + return regmap_read(st->regmap, reg, readval); 1609 + 1610 + return regmap_write(st->regmap, reg, writeval); 1611 + } 1612 + 1613 + static int adxl380_set_watermark(struct iio_dev *indio_dev, unsigned int val) 1614 + { 1615 + struct adxl380_state *st = iio_priv(indio_dev); 1616 + 1617 + st->watermark = min(val, ADXL380_FIFO_SAMPLES); 1618 + 1619 + return 0; 1620 + } 1621 + 1622 + static const struct iio_info adxl380_info = { 1623 + .read_raw = adxl380_read_raw, 1624 + .read_avail = &adxl380_read_avail, 1625 + .write_raw = adxl380_write_raw, 1626 + .write_raw_get_fmt = adxl380_write_raw_get_fmt, 1627 + .read_event_config = adxl380_read_event_config, 1628 + .write_event_config = adxl380_write_event_config, 1629 + .read_event_value = adxl380_read_event_value, 1630 + .write_event_value = adxl380_write_event_value, 1631 + .event_attrs = &adxl380_event_attribute_group, 1632 + .debugfs_reg_access = &adxl380_reg_access, 1633 + .hwfifo_set_watermark = adxl380_set_watermark, 1634 + }; 1635 + 1636 + static const struct iio_event_spec adxl380_events[] = { 1637 + { 1638 + .type = IIO_EV_TYPE_THRESH, 1639 + .dir = IIO_EV_DIR_RISING, 1640 + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | 1641 + BIT(IIO_EV_INFO_VALUE) | 1642 + BIT(IIO_EV_INFO_PERIOD), 1643 + }, 1644 + { 1645 + .type = IIO_EV_TYPE_THRESH, 1646 + .dir = IIO_EV_DIR_FALLING, 1647 + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | 1648 + BIT(IIO_EV_INFO_VALUE) | 1649 + BIT(IIO_EV_INFO_PERIOD), 1650 + }, 1651 + { 1652 + .type = IIO_EV_TYPE_GESTURE, 1653 + .dir = IIO_EV_DIR_SINGLETAP, 1654 + .mask_separate = BIT(IIO_EV_INFO_ENABLE), 1655 + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 1656 + BIT(IIO_EV_INFO_RESET_TIMEOUT), 1657 + }, 1658 + { 1659 + .type = IIO_EV_TYPE_GESTURE, 1660 + .dir = IIO_EV_DIR_DOUBLETAP, 1661 + .mask_separate = BIT(IIO_EV_INFO_ENABLE), 1662 + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 1663 + BIT(IIO_EV_INFO_RESET_TIMEOUT) | 1664 + BIT(IIO_EV_INFO_TAP2_MIN_DELAY), 1665 + }, 1666 + }; 1667 + 1668 + #define ADXL380_ACCEL_CHANNEL(index, reg, axis) { \ 1669 + .type = IIO_ACCEL, \ 1670 + .address = reg, \ 1671 + .modified = 1, \ 1672 + .channel2 = IIO_MOD_##axis, \ 1673 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 1674 + BIT(IIO_CHAN_INFO_CALIBBIAS), \ 1675 + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 1676 + .info_mask_shared_by_all_available = \ 1677 + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 1678 + .info_mask_shared_by_type = \ 1679 + BIT(IIO_CHAN_INFO_SCALE) | \ 1680 + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ 1681 + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ 1682 + .info_mask_shared_by_type_available = \ 1683 + BIT(IIO_CHAN_INFO_SCALE) | \ 1684 + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ 1685 + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ 1686 + .scan_index = index, \ 1687 + .scan_type = { \ 1688 + .sign = 's', \ 1689 + .realbits = 16, \ 1690 + .storagebits = 16, \ 1691 + .endianness = IIO_BE, \ 1692 + }, \ 1693 + .event_spec = adxl380_events, \ 1694 + .num_event_specs = ARRAY_SIZE(adxl380_events) \ 1695 + } 1696 + 1697 + static const struct iio_chan_spec adxl380_channels[] = { 1698 + ADXL380_ACCEL_CHANNEL(0, ADXL380_X_DATA_H_REG, X), 1699 + ADXL380_ACCEL_CHANNEL(1, ADXL380_Y_DATA_H_REG, Y), 1700 + ADXL380_ACCEL_CHANNEL(2, ADXL380_Z_DATA_H_REG, Z), 1701 + { 1702 + .type = IIO_TEMP, 1703 + .address = ADXL380_T_DATA_H_REG, 1704 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 1705 + BIT(IIO_CHAN_INFO_SCALE) | 1706 + BIT(IIO_CHAN_INFO_OFFSET), 1707 + .scan_index = 3, 1708 + .scan_type = { 1709 + .sign = 's', 1710 + .realbits = 12, 1711 + .storagebits = 16, 1712 + .shift = 4, 1713 + .endianness = IIO_BE, 1714 + }, 1715 + }, 1716 + }; 1717 + 1718 + static int adxl380_config_irq(struct iio_dev *indio_dev) 1719 + { 1720 + struct adxl380_state *st = iio_priv(indio_dev); 1721 + unsigned long irq_flag; 1722 + struct irq_data *desc; 1723 + u32 irq_type; 1724 + u8 polarity; 1725 + int ret; 1726 + 1727 + st->irq = fwnode_irq_get_byname(dev_fwnode(st->dev), "INT0"); 1728 + if (st->irq > 0) { 1729 + st->int_map[0] = ADXL380_INT0_MAP0_REG; 1730 + st->int_map[1] = ADXL380_INT0_MAP1_REG; 1731 + } else { 1732 + st->irq = fwnode_irq_get_byname(dev_fwnode(st->dev), "INT1"); 1733 + if (st->irq > 0) 1734 + return dev_err_probe(st->dev, -ENODEV, 1735 + "no interrupt name specified"); 1736 + st->int_map[0] = ADXL380_INT1_MAP0_REG; 1737 + st->int_map[1] = ADXL380_INT1_MAP1_REG; 1738 + } 1739 + 1740 + desc = irq_get_irq_data(st->irq); 1741 + if (!desc) 1742 + return dev_err_probe(st->dev, -EINVAL, "Could not find IRQ %d\n", st->irq); 1743 + 1744 + irq_type = irqd_get_trigger_type(desc); 1745 + if (irq_type == IRQ_TYPE_LEVEL_HIGH) { 1746 + polarity = 0; 1747 + irq_flag = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; 1748 + } else if (irq_type == IRQ_TYPE_LEVEL_LOW) { 1749 + polarity = 1; 1750 + irq_flag = IRQF_TRIGGER_LOW | IRQF_ONESHOT; 1751 + } else { 1752 + return dev_err_probe(st->dev, -EINVAL, 1753 + "Invalid interrupt 0x%x. Only level interrupts supported\n", 1754 + irq_type); 1755 + } 1756 + 1757 + ret = regmap_update_bits(st->regmap, ADXL380_INT0_REG, 1758 + ADXL380_INT0_POL_MSK, 1759 + FIELD_PREP(ADXL380_INT0_POL_MSK, polarity)); 1760 + if (ret) 1761 + return ret; 1762 + 1763 + return devm_request_threaded_irq(st->dev, st->irq, NULL, 1764 + adxl380_irq_handler, irq_flag, 1765 + indio_dev->name, indio_dev); 1766 + } 1767 + 1768 + static int adxl380_setup(struct iio_dev *indio_dev) 1769 + { 1770 + unsigned int reg_val; 1771 + u16 part_id, chip_id; 1772 + int ret, i; 1773 + struct adxl380_state *st = iio_priv(indio_dev); 1774 + 1775 + ret = regmap_read(st->regmap, ADXL380_DEVID_AD_REG, &reg_val); 1776 + if (ret) 1777 + return ret; 1778 + 1779 + if (reg_val != ADXL380_DEVID_AD_VAL) 1780 + dev_warn(st->dev, "Unknown chip id %x\n", reg_val); 1781 + 1782 + ret = regmap_bulk_read(st->regmap, ADLX380_PART_ID_REG, 1783 + &st->transf_buf, 2); 1784 + if (ret) 1785 + return ret; 1786 + 1787 + part_id = get_unaligned_be16(st->transf_buf); 1788 + part_id >>= 4; 1789 + 1790 + if (part_id != ADXL380_ID_VAL) 1791 + dev_warn(st->dev, "Unknown part id %x\n", part_id); 1792 + 1793 + ret = regmap_read(st->regmap, ADXL380_MISC_0_REG, &reg_val); 1794 + if (ret) 1795 + return ret; 1796 + 1797 + /* Bit to differentiate between ADXL380/382. */ 1798 + if (reg_val & ADXL380_XL382_MSK) 1799 + chip_id = ADXL382_ID_VAL; 1800 + else 1801 + chip_id = ADXL380_ID_VAL; 1802 + 1803 + if (chip_id != st->chip_info->chip_id) 1804 + dev_warn(st->dev, "Unknown chip id %x\n", chip_id); 1805 + 1806 + ret = regmap_write(st->regmap, ADXL380_RESET_REG, ADXL380_RESET_CODE); 1807 + if (ret) 1808 + return ret; 1809 + 1810 + /* 1811 + * A latency of approximately 0.5 ms is required after soft reset. 1812 + * Stated in the register REG_RESET description. 1813 + */ 1814 + fsleep(500); 1815 + 1816 + for (i = 0; i < indio_dev->num_channels; i++) { 1817 + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, 1818 + ADXL380_CHAN_EN_MSK(i), 1819 + 1 << (4 + i)); 1820 + if (ret) 1821 + return ret; 1822 + } 1823 + 1824 + ret = regmap_update_bits(st->regmap, ADXL380_FIFO_CONFIG_0_REG, 1825 + ADXL380_FIFO_MODE_MSK, 1826 + FIELD_PREP(ADXL380_FIFO_MODE_MSK, ADXL380_FIFO_STREAMED)); 1827 + if (ret) 1828 + return ret; 1829 + 1830 + /* Select all 3 axis for act/inact detection. */ 1831 + ret = regmap_update_bits(st->regmap, ADXL380_SNSR_AXIS_EN_REG, 1832 + ADXL380_ACT_INACT_AXIS_EN_MSK, 1833 + FIELD_PREP(ADXL380_ACT_INACT_AXIS_EN_MSK, 1834 + ADXL380_ACT_INACT_AXIS_EN_MSK)); 1835 + if (ret) 1836 + return ret; 1837 + 1838 + ret = adxl380_config_irq(indio_dev); 1839 + if (ret) 1840 + return ret; 1841 + 1842 + ret = adxl380_fill_lpf_tbl(st); 1843 + if (ret) 1844 + return ret; 1845 + 1846 + ret = adxl380_fill_hpf_tbl(st); 1847 + if (ret) 1848 + return ret; 1849 + 1850 + return adxl380_set_measure_en(st, true); 1851 + } 1852 + 1853 + int adxl380_probe(struct device *dev, struct regmap *regmap, 1854 + const struct adxl380_chip_info *chip_info) 1855 + { 1856 + struct iio_dev *indio_dev; 1857 + struct adxl380_state *st; 1858 + int ret; 1859 + 1860 + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 1861 + if (!indio_dev) 1862 + return -ENOMEM; 1863 + 1864 + st = iio_priv(indio_dev); 1865 + 1866 + st->dev = dev; 1867 + st->regmap = regmap; 1868 + st->chip_info = chip_info; 1869 + 1870 + mutex_init(&st->lock); 1871 + 1872 + indio_dev->channels = adxl380_channels; 1873 + indio_dev->num_channels = ARRAY_SIZE(adxl380_channels); 1874 + indio_dev->name = chip_info->name; 1875 + indio_dev->info = &adxl380_info; 1876 + indio_dev->modes = INDIO_DIRECT_MODE; 1877 + 1878 + ret = devm_regulator_get_enable(dev, "vddio"); 1879 + if (ret) 1880 + return dev_err_probe(st->dev, ret, 1881 + "Failed to get vddio regulator\n"); 1882 + 1883 + ret = devm_regulator_get_enable(st->dev, "vsupply"); 1884 + if (ret) 1885 + return dev_err_probe(st->dev, ret, 1886 + "Failed to get vsupply regulator\n"); 1887 + 1888 + ret = adxl380_setup(indio_dev); 1889 + if (ret) 1890 + return ret; 1891 + 1892 + ret = devm_iio_kfifo_buffer_setup_ext(st->dev, indio_dev, 1893 + &adxl380_buffer_ops, 1894 + adxl380_fifo_attributes); 1895 + if (ret) 1896 + return ret; 1897 + 1898 + return devm_iio_device_register(dev, indio_dev); 1899 + } 1900 + EXPORT_SYMBOL_NS_GPL(adxl380_probe, IIO_ADXL380); 1901 + 1902 + MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>"); 1903 + MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); 1904 + MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer driver"); 1905 + MODULE_LICENSE("GPL");
+26
drivers/iio/accel/adxl380.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + /* 3 + * ADXL380 3-Axis Digital Accelerometer 4 + * 5 + * Copyright 2024 Analog Devices Inc. 6 + */ 7 + 8 + #ifndef _ADXL380_H_ 9 + #define _ADXL380_H_ 10 + 11 + struct adxl380_chip_info { 12 + const char *name; 13 + const int scale_tbl[3][2]; 14 + const int samp_freq_tbl[3]; 15 + const int temp_offset; 16 + const u16 chip_id; 17 + }; 18 + 19 + extern const struct adxl380_chip_info adxl380_chip_info; 20 + extern const struct adxl380_chip_info adxl382_chip_info; 21 + 22 + int adxl380_probe(struct device *dev, struct regmap *regmap, 23 + const struct adxl380_chip_info *chip_info); 24 + bool adxl380_readable_noinc_reg(struct device *dev, unsigned int reg); 25 + 26 + #endif /* _ADXL380_H_ */
+64
drivers/iio/accel/adxl380_i2c.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * ADXL380 3-Axis Digital Accelerometer I2C driver 4 + * 5 + * Copyright 2024 Analog Devices Inc. 6 + */ 7 + 8 + #include <linux/i2c.h> 9 + #include <linux/mod_devicetable.h> 10 + #include <linux/module.h> 11 + #include <linux/regmap.h> 12 + 13 + #include "adxl380.h" 14 + 15 + static const struct regmap_config adxl380_regmap_config = { 16 + .reg_bits = 8, 17 + .val_bits = 8, 18 + .readable_noinc_reg = adxl380_readable_noinc_reg, 19 + }; 20 + 21 + static int adxl380_i2c_probe(struct i2c_client *client) 22 + { 23 + struct regmap *regmap; 24 + const struct adxl380_chip_info *chip_data; 25 + 26 + chip_data = i2c_get_match_data(client); 27 + 28 + regmap = devm_regmap_init_i2c(client, &adxl380_regmap_config); 29 + if (IS_ERR(regmap)) 30 + return PTR_ERR(regmap); 31 + 32 + return adxl380_probe(&client->dev, regmap, chip_data); 33 + } 34 + 35 + static const struct i2c_device_id adxl380_i2c_id[] = { 36 + { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, 37 + { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, 38 + { } 39 + }; 40 + MODULE_DEVICE_TABLE(i2c, adxl380_i2c_id); 41 + 42 + static const struct of_device_id adxl380_of_match[] = { 43 + { .compatible = "adi,adxl380", .data = &adxl380_chip_info }, 44 + { .compatible = "adi,adxl382", .data = &adxl382_chip_info }, 45 + { } 46 + }; 47 + MODULE_DEVICE_TABLE(of, adxl380_of_match); 48 + 49 + static struct i2c_driver adxl380_i2c_driver = { 50 + .driver = { 51 + .name = "adxl380_i2c", 52 + .of_match_table = adxl380_of_match, 53 + }, 54 + .probe = adxl380_i2c_probe, 55 + .id_table = adxl380_i2c_id, 56 + }; 57 + 58 + module_i2c_driver(adxl380_i2c_driver); 59 + 60 + MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>"); 61 + MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); 62 + MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer I2C driver"); 63 + MODULE_LICENSE("GPL"); 64 + MODULE_IMPORT_NS(IIO_ADXL380);
+66
drivers/iio/accel/adxl380_spi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * ADXL380 3-Axis Digital Accelerometer SPI driver 4 + * 5 + * Copyright 2024 Analog Devices Inc. 6 + */ 7 + 8 + #include <linux/mod_devicetable.h> 9 + #include <linux/module.h> 10 + #include <linux/regmap.h> 11 + #include <linux/spi/spi.h> 12 + 13 + #include "adxl380.h" 14 + 15 + static const struct regmap_config adxl380_spi_regmap_config = { 16 + .reg_bits = 7, 17 + .pad_bits = 1, 18 + .val_bits = 8, 19 + .read_flag_mask = BIT(0), 20 + .readable_noinc_reg = adxl380_readable_noinc_reg, 21 + }; 22 + 23 + static int adxl380_spi_probe(struct spi_device *spi) 24 + { 25 + const struct adxl380_chip_info *chip_data; 26 + struct regmap *regmap; 27 + 28 + chip_data = spi_get_device_match_data(spi); 29 + 30 + regmap = devm_regmap_init_spi(spi, &adxl380_spi_regmap_config); 31 + if (IS_ERR(regmap)) 32 + return PTR_ERR(regmap); 33 + 34 + return adxl380_probe(&spi->dev, regmap, chip_data); 35 + } 36 + 37 + static const struct spi_device_id adxl380_spi_id[] = { 38 + { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, 39 + { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, 40 + { } 41 + }; 42 + MODULE_DEVICE_TABLE(spi, adxl380_spi_id); 43 + 44 + static const struct of_device_id adxl380_of_match[] = { 45 + { .compatible = "adi,adxl380", .data = &adxl380_chip_info }, 46 + { .compatible = "adi,adxl382", .data = &adxl382_chip_info }, 47 + { } 48 + }; 49 + MODULE_DEVICE_TABLE(of, adxl380_of_match); 50 + 51 + static struct spi_driver adxl380_spi_driver = { 52 + .driver = { 53 + .name = "adxl380_spi", 54 + .of_match_table = adxl380_of_match, 55 + }, 56 + .probe = adxl380_spi_probe, 57 + .id_table = adxl380_spi_id, 58 + }; 59 + 60 + module_spi_driver(adxl380_spi_driver); 61 + 62 + MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>"); 63 + MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); 64 + MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer SPI driver"); 65 + MODULE_LICENSE("GPL"); 66 + MODULE_IMPORT_NS(IIO_ADXL380);