1906 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * ADXL380 3-Axis Digital Accelerometer core driver4 *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 <linux/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 38029#define ADXL382_ID_VAL 38230 31#define ADXL380_DEVID_AD_REG 0x0032#define ADLX380_PART_ID_REG 0x0233 34#define ADXL380_X_DATA_H_REG 0x1535#define ADXL380_Y_DATA_H_REG 0x1736#define ADXL380_Z_DATA_H_REG 0x1937#define ADXL380_T_DATA_H_REG 0x1B38 39#define ADXL380_MISC_0_REG 0x2040#define ADXL380_XL382_MSK BIT(7)41 42#define ADXL380_MISC_1_REG 0x2143 44#define ADXL380_X_DSM_OFFSET_REG 0x4D45 46#define ADXL380_ACT_INACT_CTL_REG 0x3747#define ADXL380_INACT_EN_MSK BIT(2)48#define ADXL380_ACT_EN_MSK BIT(0)49 50#define ADXL380_SNSR_AXIS_EN_REG 0x3851#define ADXL380_ACT_INACT_AXIS_EN_MSK GENMASK(2, 0)52 53#define ADXL380_THRESH_ACT_H_REG 0x3954#define ADXL380_TIME_ACT_H_REG 0x3B55#define ADXL380_THRESH_INACT_H_REG 0x3E56#define ADXL380_TIME_INACT_H_REG 0x4057#define ADXL380_THRESH_MAX GENMASK(12, 0)58#define ADXL380_TIME_MAX GENMASK(24, 0)59 60#define ADXL380_FIFO_CONFIG_0_REG 0x3061#define ADXL380_FIFO_SAMPLES_8_MSK BIT(0)62#define ADXL380_FIFO_MODE_MSK GENMASK(5, 4)63 64#define ADXL380_FIFO_DISABLED 065#define ADXL380_FIFO_NORMAL 166#define ADXL380_FIFO_STREAMED 267#define ADXL380_FIFO_TRIGGERED 368 69#define ADXL380_FIFO_CONFIG_1_REG 0x3170#define ADXL380_FIFO_STATUS_0_REG 0x1E71 72#define ADXL380_TAP_THRESH_REG 0x4373#define ADXL380_TAP_DUR_REG 0x4474#define ADXL380_TAP_LATENT_REG 0x4575#define ADXL380_TAP_WINDOW_REG 0x4676#define ADXL380_TAP_TIME_MAX GENMASK(7, 0)77 78#define ADXL380_TAP_CFG_REG 0x4779#define ADXL380_TAP_AXIS_MSK GENMASK(1, 0)80 81#define ADXL380_TRIG_CFG_REG 0x4982#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 0x5086#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 0x2692#define ADXL380_OP_MODE_RANGE_MSK GENMASK(7, 6)93#define ADXL380_OP_MODE_MSK GENMASK(3, 0)94#define ADXL380_OP_MODE_STANDBY 095#define ADXL380_OP_MODE_HEART_SOUND 196#define ADXL380_OP_MODE_ULP 297#define ADXL380_OP_MODE_VLP 398#define ADXL380_OP_MODE_LP 499#define ADXL380_OP_MODE_LP_ULP 6100#define ADXL380_OP_MODE_LP_VLP 7101#define ADXL380_OP_MODE_RBW 8102#define ADXL380_OP_MODE_RBW_ULP 10103#define ADXL380_OP_MODE_RBW_VLP 11104#define ADXL380_OP_MODE_HP 12105#define ADXL380_OP_MODE_HP_ULP 14106#define ADXL380_OP_MODE_HP_VLP 15107 108#define ADXL380_OP_MODE_4G_RANGE 0109#define ADXL382_OP_MODE_15G_RANGE 0110#define ADXL380_OP_MODE_8G_RANGE 1111#define ADXL382_OP_MODE_30G_RANGE 1112#define ADXL380_OP_MODE_16G_RANGE 2113#define ADXL382_OP_MODE_60G_RANGE 2114 115#define ADXL380_DIG_EN_REG 0x27116#define ADXL380_CHAN_EN_MSK(chan) BIT(4 + (chan))117#define ADXL380_FIFO_EN_MSK BIT(3)118 119#define ADXL380_INT0_MAP0_REG 0x2B120#define ADXL380_INT1_MAP0_REG 0x2D121#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 0x2C126#define ADXL380_INT1_MAP1_REG 0x2E127#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 0x5D131#define ADXL380_INT0_POL_MSK BIT(7)132 133#define ADXL380_RESET_REG 0x2A134#define ADXL380_FIFO_DATA 0x1D135 136#define ADXL380_DEVID_AD_VAL 0xAD137#define ADXL380_RESET_CODE 0x52138 139#define ADXL380_STATUS_0_REG 0x11140#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 315UL149 150enum adxl380_channels {151 ADXL380_ACCEL_X,152 ADXL380_ACCEL_Y,153 ADXL380_ACCEL_Z,154 ADXL380_TEMP,155 ADXL380_CH_NUM156};157 158enum adxl380_axis {159 ADXL380_X_AXIS,160 ADXL380_Y_AXIS,161 ADXL380_Z_AXIS,162};163 164enum adxl380_activity_type {165 ADXL380_ACTIVITY,166 ADXL380_INACTIVITY,167};168 169enum adxl380_tap_type {170 ADXL380_SINGLE_TAP,171 ADXL380_DOUBLE_TAP,172};173 174enum adxl380_tap_time_type {175 ADXL380_TAP_TIME_LATENT,176 ADXL380_TAP_TIME_WINDOW,177};178 179static const int adxl380_range_scale_factor_tbl[] = { 1, 2, 4 };180 181const 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 degC192 * and a sensitivity of 10.2 LSB/C.193 */194 .temp_offset = 25 * 102 / 10 - 470,195 196};197EXPORT_SYMBOL_NS_GPL(adxl380_chip_info, IIO_ADXL380);198 199const 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 degC210 * and a sensitivity of 10.2 LSB/C.211 */212 .temp_offset = 25 * 102 / 10 - 570,213};214EXPORT_SYMBOL_NS_GPL(adxl382_chip_info, IIO_ADXL380);215 216static 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 221static 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 226static 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 231struct 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 atomicity237 * 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 262bool adxl380_readable_noinc_reg(struct device *dev, unsigned int reg)263{264 return reg == ADXL380_FIFO_DATA;265}266EXPORT_SYMBOL_NS_GPL(adxl380_readable_noinc_reg, IIO_ADXL380);267 268static 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 else284 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 292static 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 304static 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 else325 st->inact_threshold = th;326 327 return 0;328}329 330static 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 350static 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 370static 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 else390 st->tap_latent_us = us;391 392 return 0;393}394 395static 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 413static 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 433static 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 446static 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 463static const int adxl380_lpf_div[] = {464 1, 4, 8, 16,465};466 467static 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 482static const int adxl380_hpf_mul[] = {483 0, 247000, 62084, 15545, 3862, 954, 238,484};485 486static 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 509static 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 542static 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 555static 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 567static 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 585static 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 614static 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 633static 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 662static 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 else682 st->inact_time_ms = ms;683 684 return 0;685}686 687static 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 706static 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 741static 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 755static 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], ®_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 else771 *en = FIELD_GET(ADXL380_INT_MAP0_INACT_INT0_MSK, reg_val);772 773 return 0;774}775 776static 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 790static 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 813static 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 830static 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], ®_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 else842 *en = FIELD_GET(ADXL380_INT_MAP1_DOUBLE_TAP_INT0_MSK, reg_val);843 844 return 0;845}846 847static 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 859static 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 883static 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 899static 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 915static 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 929static 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 956static 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 992static 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 1011static 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, ®_val);1021 if (ret)1022 return ret;1023 1024 *calibbias = sign_extend32(reg_val, 7);1025 1026 return 0;1027}1028 1029static 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 1036static 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 1043static 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 1053static 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, ®_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 1070static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);1071static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);1072static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,1073 adxl380_get_fifo_watermark, NULL, 0);1074static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,1075 adxl380_get_fifo_enabled, NULL, 0);1076 1077static 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 NULL1083};1084 1085static 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 iio_get_masklength(indio_dev));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 1130static 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 1164static const struct iio_buffer_setup_ops adxl380_buffer_ops = {1165 .postenable = adxl380_buffer_postenable,1166 .predisable = adxl380_buffer_predisable,1167};1168 1169static 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 1244static 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 1281static 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 1320static 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 1335static 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 1385static 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 1422static 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 1485static 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 1548static 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 1564static 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 1589static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_maxtomin_time, 0);1590 1591static struct attribute *adxl380_event_attributes[] = {1592 &iio_dev_attr_in_accel_gesture_tap_maxtomin_time.dev_attr.attr,1593 NULL1594};1595 1596static const struct attribute_group adxl380_event_attribute_group = {1597 .attrs = adxl380_event_attributes,1598};1599 1600static 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 1613static 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 1622static 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 1636static 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 1697static 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 1718static 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 1768static 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, ®_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, ®_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 else1801 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 1853int 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}1900EXPORT_SYMBOL_NS_GPL(adxl380_probe, IIO_ADXL380);1901 1902MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>");1903MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");1904MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer driver");1905MODULE_LICENSE("GPL");1906