18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 3-axis accelerometer driver supporting following Bosch-Sensortec chips: 48c2ecf20Sopenharmony_ci * - BMC150 58c2ecf20Sopenharmony_ci * - BMI055 68c2ecf20Sopenharmony_ci * - BMA255 78c2ecf20Sopenharmony_ci * - BMA250E 88c2ecf20Sopenharmony_ci * - BMA222E 98c2ecf20Sopenharmony_ci * - BMA280 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (c) 2014, Intel Corporation. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/i2c.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/acpi.h> 208c2ecf20Sopenharmony_ci#include <linux/pm.h> 218c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 228c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 238c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 248c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h> 258c2ecf20Sopenharmony_ci#include <linux/iio/events.h> 268c2ecf20Sopenharmony_ci#include <linux/iio/trigger.h> 278c2ecf20Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 288c2ecf20Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 298c2ecf20Sopenharmony_ci#include <linux/regmap.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "bmc150-accel.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define BMC150_ACCEL_DRV_NAME "bmc150_accel" 348c2ecf20Sopenharmony_ci#define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_CHIP_ID 0x00 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_INT_STATUS_2 0x0B 398c2ecf20Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_MASK 0x07 408c2ecf20Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_BIT_X BIT(0) 418c2ecf20Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_BIT_Y BIT(1) 428c2ecf20Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_BIT_Z BIT(2) 438c2ecf20Sopenharmony_ci#define BMC150_ACCEL_ANY_MOTION_BIT_SIGN BIT(3) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_PMU_LPW 0x11 468c2ecf20Sopenharmony_ci#define BMC150_ACCEL_PMU_MODE_MASK 0xE0 478c2ecf20Sopenharmony_ci#define BMC150_ACCEL_PMU_MODE_SHIFT 5 488c2ecf20Sopenharmony_ci#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_MASK 0x17 498c2ecf20Sopenharmony_ci#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT 1 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_PMU_RANGE 0x0F 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define BMC150_ACCEL_DEF_RANGE_2G 0x03 548c2ecf20Sopenharmony_ci#define BMC150_ACCEL_DEF_RANGE_4G 0x05 558c2ecf20Sopenharmony_ci#define BMC150_ACCEL_DEF_RANGE_8G 0x08 568c2ecf20Sopenharmony_ci#define BMC150_ACCEL_DEF_RANGE_16G 0x0C 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Default BW: 125Hz */ 598c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_PMU_BW 0x10 608c2ecf20Sopenharmony_ci#define BMC150_ACCEL_DEF_BW 125 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_RESET 0x14 638c2ecf20Sopenharmony_ci#define BMC150_ACCEL_RESET_VAL 0xB6 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_INT_MAP_0 0x19 668c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_INT_MAP_1 0x1A 698c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0) 708c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_1_BIT_FWM BIT(1) 718c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL BIT(2) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_INT_RST_LATCH 0x21 748c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80 758c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_MODE_LATCH_INT 0x0F 768c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_MODE_NON_LATCH_INT 0x00 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_INT_EN_0 0x16 798c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_SLP_X BIT(0) 808c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_SLP_Y BIT(1) 818c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_SLP_Z BIT(2) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_INT_EN_1 0x17 848c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_DATA_EN BIT(4) 858c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN BIT(5) 868c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_EN_BIT_FWM_EN BIT(6) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20 898c2ecf20Sopenharmony_ci#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0) 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_INT_5 0x27 928c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLOPE_DUR_MASK 0x03 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_INT_6 0x28 958c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLOPE_THRES_MASK 0xFF 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* Slope duration in terms of number of samples */ 988c2ecf20Sopenharmony_ci#define BMC150_ACCEL_DEF_SLOPE_DURATION 1 998c2ecf20Sopenharmony_ci/* in terms of multiples of g's/LSB, based on range */ 1008c2ecf20Sopenharmony_ci#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD 1 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_XOUT_L 0x02 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define BMC150_ACCEL_MAX_STARTUP_TIME_MS 100 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Sleep Duration values */ 1078c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_500_MICRO 0x05 1088c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_1_MS 0x06 1098c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_2_MS 0x07 1108c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_4_MS 0x08 1118c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_6_MS 0x09 1128c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_10_MS 0x0A 1138c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_25_MS 0x0B 1148c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_50_MS 0x0C 1158c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_100_MS 0x0D 1168c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_500_MS 0x0E 1178c2ecf20Sopenharmony_ci#define BMC150_ACCEL_SLEEP_1_SEC 0x0F 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_TEMP 0x08 1208c2ecf20Sopenharmony_ci#define BMC150_ACCEL_TEMP_CENTER_VAL 23 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define BMC150_ACCEL_AXIS_TO_REG(axis) (BMC150_ACCEL_REG_XOUT_L + (axis * 2)) 1238c2ecf20Sopenharmony_ci#define BMC150_AUTO_SUSPEND_DELAY_MS 2000 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_FIFO_STATUS 0x0E 1268c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_FIFO_CONFIG0 0x30 1278c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_FIFO_CONFIG1 0x3E 1288c2ecf20Sopenharmony_ci#define BMC150_ACCEL_REG_FIFO_DATA 0x3F 1298c2ecf20Sopenharmony_ci#define BMC150_ACCEL_FIFO_LENGTH 32 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cienum bmc150_accel_axis { 1328c2ecf20Sopenharmony_ci AXIS_X, 1338c2ecf20Sopenharmony_ci AXIS_Y, 1348c2ecf20Sopenharmony_ci AXIS_Z, 1358c2ecf20Sopenharmony_ci AXIS_MAX, 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cienum bmc150_power_modes { 1398c2ecf20Sopenharmony_ci BMC150_ACCEL_SLEEP_MODE_NORMAL, 1408c2ecf20Sopenharmony_ci BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 1418c2ecf20Sopenharmony_ci BMC150_ACCEL_SLEEP_MODE_LPM, 1428c2ecf20Sopenharmony_ci BMC150_ACCEL_SLEEP_MODE_SUSPEND = 0x04, 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistruct bmc150_scale_info { 1468c2ecf20Sopenharmony_ci int scale; 1478c2ecf20Sopenharmony_ci u8 reg_range; 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistruct bmc150_accel_chip_info { 1518c2ecf20Sopenharmony_ci const char *name; 1528c2ecf20Sopenharmony_ci u8 chip_id; 1538c2ecf20Sopenharmony_ci const struct iio_chan_spec *channels; 1548c2ecf20Sopenharmony_ci int num_channels; 1558c2ecf20Sopenharmony_ci const struct bmc150_scale_info scale_table[4]; 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistruct bmc150_accel_interrupt { 1598c2ecf20Sopenharmony_ci const struct bmc150_accel_interrupt_info *info; 1608c2ecf20Sopenharmony_ci atomic_t users; 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistruct bmc150_accel_trigger { 1648c2ecf20Sopenharmony_ci struct bmc150_accel_data *data; 1658c2ecf20Sopenharmony_ci struct iio_trigger *indio_trig; 1668c2ecf20Sopenharmony_ci int (*setup)(struct bmc150_accel_trigger *t, bool state); 1678c2ecf20Sopenharmony_ci int intr; 1688c2ecf20Sopenharmony_ci bool enabled; 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cienum bmc150_accel_interrupt_id { 1728c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_DATA_READY, 1738c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_ANY_MOTION, 1748c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_WATERMARK, 1758c2ecf20Sopenharmony_ci BMC150_ACCEL_INTERRUPTS, 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cienum bmc150_accel_trigger_id { 1798c2ecf20Sopenharmony_ci BMC150_ACCEL_TRIGGER_DATA_READY, 1808c2ecf20Sopenharmony_ci BMC150_ACCEL_TRIGGER_ANY_MOTION, 1818c2ecf20Sopenharmony_ci BMC150_ACCEL_TRIGGERS, 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistruct bmc150_accel_data { 1858c2ecf20Sopenharmony_ci struct regmap *regmap; 1868c2ecf20Sopenharmony_ci int irq; 1878c2ecf20Sopenharmony_ci struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS]; 1888c2ecf20Sopenharmony_ci struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS]; 1898c2ecf20Sopenharmony_ci struct mutex mutex; 1908c2ecf20Sopenharmony_ci u8 fifo_mode, watermark; 1918c2ecf20Sopenharmony_ci s16 buffer[8]; 1928c2ecf20Sopenharmony_ci /* 1938c2ecf20Sopenharmony_ci * Ensure there is sufficient space and correct alignment for 1948c2ecf20Sopenharmony_ci * the timestamp if enabled 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci struct { 1978c2ecf20Sopenharmony_ci __le16 channels[3]; 1988c2ecf20Sopenharmony_ci s64 ts __aligned(8); 1998c2ecf20Sopenharmony_ci } scan; 2008c2ecf20Sopenharmony_ci u8 bw_bits; 2018c2ecf20Sopenharmony_ci u32 slope_dur; 2028c2ecf20Sopenharmony_ci u32 slope_thres; 2038c2ecf20Sopenharmony_ci u32 range; 2048c2ecf20Sopenharmony_ci int ev_enable_state; 2058c2ecf20Sopenharmony_ci int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ 2068c2ecf20Sopenharmony_ci const struct bmc150_accel_chip_info *chip_info; 2078c2ecf20Sopenharmony_ci struct iio_mount_matrix orientation; 2088c2ecf20Sopenharmony_ci}; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic const struct { 2118c2ecf20Sopenharmony_ci int val; 2128c2ecf20Sopenharmony_ci int val2; 2138c2ecf20Sopenharmony_ci u8 bw_bits; 2148c2ecf20Sopenharmony_ci} bmc150_accel_samp_freq_table[] = { {15, 620000, 0x08}, 2158c2ecf20Sopenharmony_ci {31, 260000, 0x09}, 2168c2ecf20Sopenharmony_ci {62, 500000, 0x0A}, 2178c2ecf20Sopenharmony_ci {125, 0, 0x0B}, 2188c2ecf20Sopenharmony_ci {250, 0, 0x0C}, 2198c2ecf20Sopenharmony_ci {500, 0, 0x0D}, 2208c2ecf20Sopenharmony_ci {1000, 0, 0x0E}, 2218c2ecf20Sopenharmony_ci {2000, 0, 0x0F} }; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic const struct { 2248c2ecf20Sopenharmony_ci int bw_bits; 2258c2ecf20Sopenharmony_ci int msec; 2268c2ecf20Sopenharmony_ci} bmc150_accel_sample_upd_time[] = { {0x08, 64}, 2278c2ecf20Sopenharmony_ci {0x09, 32}, 2288c2ecf20Sopenharmony_ci {0x0A, 16}, 2298c2ecf20Sopenharmony_ci {0x0B, 8}, 2308c2ecf20Sopenharmony_ci {0x0C, 4}, 2318c2ecf20Sopenharmony_ci {0x0D, 2}, 2328c2ecf20Sopenharmony_ci {0x0E, 1}, 2338c2ecf20Sopenharmony_ci {0x0F, 1} }; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic const struct { 2368c2ecf20Sopenharmony_ci int sleep_dur; 2378c2ecf20Sopenharmony_ci u8 reg_value; 2388c2ecf20Sopenharmony_ci} bmc150_accel_sleep_value_table[] = { {0, 0}, 2398c2ecf20Sopenharmony_ci {500, BMC150_ACCEL_SLEEP_500_MICRO}, 2408c2ecf20Sopenharmony_ci {1000, BMC150_ACCEL_SLEEP_1_MS}, 2418c2ecf20Sopenharmony_ci {2000, BMC150_ACCEL_SLEEP_2_MS}, 2428c2ecf20Sopenharmony_ci {4000, BMC150_ACCEL_SLEEP_4_MS}, 2438c2ecf20Sopenharmony_ci {6000, BMC150_ACCEL_SLEEP_6_MS}, 2448c2ecf20Sopenharmony_ci {10000, BMC150_ACCEL_SLEEP_10_MS}, 2458c2ecf20Sopenharmony_ci {25000, BMC150_ACCEL_SLEEP_25_MS}, 2468c2ecf20Sopenharmony_ci {50000, BMC150_ACCEL_SLEEP_50_MS}, 2478c2ecf20Sopenharmony_ci {100000, BMC150_ACCEL_SLEEP_100_MS}, 2488c2ecf20Sopenharmony_ci {500000, BMC150_ACCEL_SLEEP_500_MS}, 2498c2ecf20Sopenharmony_ci {1000000, BMC150_ACCEL_SLEEP_1_SEC} }; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciconst struct regmap_config bmc150_regmap_conf = { 2528c2ecf20Sopenharmony_ci .reg_bits = 8, 2538c2ecf20Sopenharmony_ci .val_bits = 8, 2548c2ecf20Sopenharmony_ci .max_register = 0x3f, 2558c2ecf20Sopenharmony_ci}; 2568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bmc150_regmap_conf); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int bmc150_accel_set_mode(struct bmc150_accel_data *data, 2598c2ecf20Sopenharmony_ci enum bmc150_power_modes mode, 2608c2ecf20Sopenharmony_ci int dur_us) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 2638c2ecf20Sopenharmony_ci int i; 2648c2ecf20Sopenharmony_ci int ret; 2658c2ecf20Sopenharmony_ci u8 lpw_bits; 2668c2ecf20Sopenharmony_ci int dur_val = -1; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (dur_us > 0) { 2698c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bmc150_accel_sleep_value_table); 2708c2ecf20Sopenharmony_ci ++i) { 2718c2ecf20Sopenharmony_ci if (bmc150_accel_sleep_value_table[i].sleep_dur == 2728c2ecf20Sopenharmony_ci dur_us) 2738c2ecf20Sopenharmony_ci dur_val = 2748c2ecf20Sopenharmony_ci bmc150_accel_sleep_value_table[i].reg_value; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci } else { 2778c2ecf20Sopenharmony_ci dur_val = 0; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (dur_val < 0) 2818c2ecf20Sopenharmony_ci return -EINVAL; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT; 2848c2ecf20Sopenharmony_ci lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci dev_dbg(dev, "Set Mode bits %x\n", lpw_bits); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_LPW, lpw_bits); 2898c2ecf20Sopenharmony_ci if (ret < 0) { 2908c2ecf20Sopenharmony_ci dev_err(dev, "Error writing reg_pmu_lpw\n"); 2918c2ecf20Sopenharmony_ci return ret; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, 2988c2ecf20Sopenharmony_ci int val2) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci int i; 3018c2ecf20Sopenharmony_ci int ret; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { 3048c2ecf20Sopenharmony_ci if (bmc150_accel_samp_freq_table[i].val == val && 3058c2ecf20Sopenharmony_ci bmc150_accel_samp_freq_table[i].val2 == val2) { 3068c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, 3078c2ecf20Sopenharmony_ci BMC150_ACCEL_REG_PMU_BW, 3088c2ecf20Sopenharmony_ci bmc150_accel_samp_freq_table[i].bw_bits); 3098c2ecf20Sopenharmony_ci if (ret < 0) 3108c2ecf20Sopenharmony_ci return ret; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci data->bw_bits = 3138c2ecf20Sopenharmony_ci bmc150_accel_samp_freq_table[i].bw_bits; 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return -EINVAL; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int bmc150_accel_update_slope(struct bmc150_accel_data *data) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 3248c2ecf20Sopenharmony_ci int ret; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_6, 3278c2ecf20Sopenharmony_ci data->slope_thres); 3288c2ecf20Sopenharmony_ci if (ret < 0) { 3298c2ecf20Sopenharmony_ci dev_err(dev, "Error writing reg_int_6\n"); 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ret = regmap_update_bits(data->regmap, BMC150_ACCEL_REG_INT_5, 3348c2ecf20Sopenharmony_ci BMC150_ACCEL_SLOPE_DUR_MASK, data->slope_dur); 3358c2ecf20Sopenharmony_ci if (ret < 0) { 3368c2ecf20Sopenharmony_ci dev_err(dev, "Error updating reg_int_5\n"); 3378c2ecf20Sopenharmony_ci return ret; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci dev_dbg(dev, "%x %x\n", data->slope_thres, data->slope_dur); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return ret; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t, 3468c2ecf20Sopenharmony_ci bool state) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci if (state) 3498c2ecf20Sopenharmony_ci return bmc150_accel_update_slope(t->data); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, 3558c2ecf20Sopenharmony_ci int *val2) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int i; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { 3608c2ecf20Sopenharmony_ci if (bmc150_accel_samp_freq_table[i].bw_bits == data->bw_bits) { 3618c2ecf20Sopenharmony_ci *val = bmc150_accel_samp_freq_table[i].val; 3628c2ecf20Sopenharmony_ci *val2 = bmc150_accel_samp_freq_table[i].val2; 3638c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return -EINVAL; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 3718c2ecf20Sopenharmony_cistatic int bmc150_accel_get_startup_times(struct bmc150_accel_data *data) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci int i; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bmc150_accel_sample_upd_time); ++i) { 3768c2ecf20Sopenharmony_ci if (bmc150_accel_sample_upd_time[i].bw_bits == data->bw_bits) 3778c2ecf20Sopenharmony_ci return bmc150_accel_sample_upd_time[i].msec; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return BMC150_ACCEL_MAX_STARTUP_TIME_MS; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 3868c2ecf20Sopenharmony_ci int ret; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (on) { 3898c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 3908c2ecf20Sopenharmony_ci } else { 3918c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 3928c2ecf20Sopenharmony_ci ret = pm_runtime_put_autosuspend(dev); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (ret < 0) { 3968c2ecf20Sopenharmony_ci dev_err(dev, 3978c2ecf20Sopenharmony_ci "Failed: %s for %d\n", __func__, on); 3988c2ecf20Sopenharmony_ci if (on) 3998c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return ret; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci#else 4078c2ecf20Sopenharmony_cistatic int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci#endif 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic const struct bmc150_accel_interrupt_info { 4148c2ecf20Sopenharmony_ci u8 map_reg; 4158c2ecf20Sopenharmony_ci u8 map_bitmask; 4168c2ecf20Sopenharmony_ci u8 en_reg; 4178c2ecf20Sopenharmony_ci u8 en_bitmask; 4188c2ecf20Sopenharmony_ci} bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = { 4198c2ecf20Sopenharmony_ci { /* data ready interrupt */ 4208c2ecf20Sopenharmony_ci .map_reg = BMC150_ACCEL_REG_INT_MAP_1, 4218c2ecf20Sopenharmony_ci .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA, 4228c2ecf20Sopenharmony_ci .en_reg = BMC150_ACCEL_REG_INT_EN_1, 4238c2ecf20Sopenharmony_ci .en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN, 4248c2ecf20Sopenharmony_ci }, 4258c2ecf20Sopenharmony_ci { /* motion interrupt */ 4268c2ecf20Sopenharmony_ci .map_reg = BMC150_ACCEL_REG_INT_MAP_0, 4278c2ecf20Sopenharmony_ci .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE, 4288c2ecf20Sopenharmony_ci .en_reg = BMC150_ACCEL_REG_INT_EN_0, 4298c2ecf20Sopenharmony_ci .en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X | 4308c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_EN_BIT_SLP_Y | 4318c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_EN_BIT_SLP_Z 4328c2ecf20Sopenharmony_ci }, 4338c2ecf20Sopenharmony_ci { /* fifo watermark interrupt */ 4348c2ecf20Sopenharmony_ci .map_reg = BMC150_ACCEL_REG_INT_MAP_1, 4358c2ecf20Sopenharmony_ci .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM, 4368c2ecf20Sopenharmony_ci .en_reg = BMC150_ACCEL_REG_INT_EN_1, 4378c2ecf20Sopenharmony_ci .en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN, 4388c2ecf20Sopenharmony_ci }, 4398c2ecf20Sopenharmony_ci}; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev, 4428c2ecf20Sopenharmony_ci struct bmc150_accel_data *data) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci int i; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++) 4478c2ecf20Sopenharmony_ci data->interrupts[i].info = &bmc150_accel_interrupts[i]; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i, 4518c2ecf20Sopenharmony_ci bool state) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 4548c2ecf20Sopenharmony_ci struct bmc150_accel_interrupt *intr = &data->interrupts[i]; 4558c2ecf20Sopenharmony_ci const struct bmc150_accel_interrupt_info *info = intr->info; 4568c2ecf20Sopenharmony_ci int ret; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (state) { 4598c2ecf20Sopenharmony_ci if (atomic_inc_return(&intr->users) > 1) 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci } else { 4628c2ecf20Sopenharmony_ci if (atomic_dec_return(&intr->users) > 0) 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* 4678c2ecf20Sopenharmony_ci * We will expect the enable and disable to do operation in reverse 4688c2ecf20Sopenharmony_ci * order. This will happen here anyway, as our resume operation uses 4698c2ecf20Sopenharmony_ci * sync mode runtime pm calls. The suspend operation will be delayed 4708c2ecf20Sopenharmony_ci * by autosuspend delay. 4718c2ecf20Sopenharmony_ci * So the disable operation will still happen in reverse order of 4728c2ecf20Sopenharmony_ci * enable operation. When runtime pm is disabled the mode is always on, 4738c2ecf20Sopenharmony_ci * so sequence doesn't matter. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci ret = bmc150_accel_set_power_state(data, state); 4768c2ecf20Sopenharmony_ci if (ret < 0) 4778c2ecf20Sopenharmony_ci return ret; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* map the interrupt to the appropriate pins */ 4808c2ecf20Sopenharmony_ci ret = regmap_update_bits(data->regmap, info->map_reg, info->map_bitmask, 4818c2ecf20Sopenharmony_ci (state ? info->map_bitmask : 0)); 4828c2ecf20Sopenharmony_ci if (ret < 0) { 4838c2ecf20Sopenharmony_ci dev_err(dev, "Error updating reg_int_map\n"); 4848c2ecf20Sopenharmony_ci goto out_fix_power_state; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* enable/disable the interrupt */ 4888c2ecf20Sopenharmony_ci ret = regmap_update_bits(data->regmap, info->en_reg, info->en_bitmask, 4898c2ecf20Sopenharmony_ci (state ? info->en_bitmask : 0)); 4908c2ecf20Sopenharmony_ci if (ret < 0) { 4918c2ecf20Sopenharmony_ci dev_err(dev, "Error updating reg_int_en\n"); 4928c2ecf20Sopenharmony_ci goto out_fix_power_state; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ciout_fix_power_state: 4988c2ecf20Sopenharmony_ci bmc150_accel_set_power_state(data, false); 4998c2ecf20Sopenharmony_ci return ret; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 5058c2ecf20Sopenharmony_ci int ret, i; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) { 5088c2ecf20Sopenharmony_ci if (data->chip_info->scale_table[i].scale == val) { 5098c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, 5108c2ecf20Sopenharmony_ci BMC150_ACCEL_REG_PMU_RANGE, 5118c2ecf20Sopenharmony_ci data->chip_info->scale_table[i].reg_range); 5128c2ecf20Sopenharmony_ci if (ret < 0) { 5138c2ecf20Sopenharmony_ci dev_err(dev, "Error writing pmu_range\n"); 5148c2ecf20Sopenharmony_ci return ret; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci data->range = data->chip_info->scale_table[i].reg_range; 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return -EINVAL; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 5288c2ecf20Sopenharmony_ci int ret; 5298c2ecf20Sopenharmony_ci unsigned int value; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_ACCEL_REG_TEMP, &value); 5348c2ecf20Sopenharmony_ci if (ret < 0) { 5358c2ecf20Sopenharmony_ci dev_err(dev, "Error reading reg_temp\n"); 5368c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5378c2ecf20Sopenharmony_ci return ret; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci *val = sign_extend32(value, 7); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return IIO_VAL_INT; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic int bmc150_accel_get_axis(struct bmc150_accel_data *data, 5478c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 5488c2ecf20Sopenharmony_ci int *val) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 5518c2ecf20Sopenharmony_ci int ret; 5528c2ecf20Sopenharmony_ci int axis = chan->scan_index; 5538c2ecf20Sopenharmony_ci __le16 raw_val; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 5568c2ecf20Sopenharmony_ci ret = bmc150_accel_set_power_state(data, true); 5578c2ecf20Sopenharmony_ci if (ret < 0) { 5588c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5598c2ecf20Sopenharmony_ci return ret; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis), 5638c2ecf20Sopenharmony_ci &raw_val, sizeof(raw_val)); 5648c2ecf20Sopenharmony_ci if (ret < 0) { 5658c2ecf20Sopenharmony_ci dev_err(dev, "Error reading axis %d\n", axis); 5668c2ecf20Sopenharmony_ci bmc150_accel_set_power_state(data, false); 5678c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5688c2ecf20Sopenharmony_ci return ret; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci *val = sign_extend32(le16_to_cpu(raw_val) >> chan->scan_type.shift, 5718c2ecf20Sopenharmony_ci chan->scan_type.realbits - 1); 5728c2ecf20Sopenharmony_ci ret = bmc150_accel_set_power_state(data, false); 5738c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5748c2ecf20Sopenharmony_ci if (ret < 0) 5758c2ecf20Sopenharmony_ci return ret; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return IIO_VAL_INT; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic int bmc150_accel_read_raw(struct iio_dev *indio_dev, 5818c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 5828c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 5858c2ecf20Sopenharmony_ci int ret; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci switch (mask) { 5888c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 5898c2ecf20Sopenharmony_ci switch (chan->type) { 5908c2ecf20Sopenharmony_ci case IIO_TEMP: 5918c2ecf20Sopenharmony_ci return bmc150_accel_get_temp(data, val); 5928c2ecf20Sopenharmony_ci case IIO_ACCEL: 5938c2ecf20Sopenharmony_ci if (iio_buffer_enabled(indio_dev)) 5948c2ecf20Sopenharmony_ci return -EBUSY; 5958c2ecf20Sopenharmony_ci else 5968c2ecf20Sopenharmony_ci return bmc150_accel_get_axis(data, chan, val); 5978c2ecf20Sopenharmony_ci default: 5988c2ecf20Sopenharmony_ci return -EINVAL; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 6018c2ecf20Sopenharmony_ci if (chan->type == IIO_TEMP) { 6028c2ecf20Sopenharmony_ci *val = BMC150_ACCEL_TEMP_CENTER_VAL; 6038c2ecf20Sopenharmony_ci return IIO_VAL_INT; 6048c2ecf20Sopenharmony_ci } else { 6058c2ecf20Sopenharmony_ci return -EINVAL; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 6088c2ecf20Sopenharmony_ci *val = 0; 6098c2ecf20Sopenharmony_ci switch (chan->type) { 6108c2ecf20Sopenharmony_ci case IIO_TEMP: 6118c2ecf20Sopenharmony_ci *val2 = 500000; 6128c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 6138c2ecf20Sopenharmony_ci case IIO_ACCEL: 6148c2ecf20Sopenharmony_ci { 6158c2ecf20Sopenharmony_ci int i; 6168c2ecf20Sopenharmony_ci const struct bmc150_scale_info *si; 6178c2ecf20Sopenharmony_ci int st_size = ARRAY_SIZE(data->chip_info->scale_table); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci for (i = 0; i < st_size; ++i) { 6208c2ecf20Sopenharmony_ci si = &data->chip_info->scale_table[i]; 6218c2ecf20Sopenharmony_ci if (si->reg_range == data->range) { 6228c2ecf20Sopenharmony_ci *val2 = si->scale; 6238c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci return -EINVAL; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci default: 6298c2ecf20Sopenharmony_ci return -EINVAL; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 6328c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 6338c2ecf20Sopenharmony_ci ret = bmc150_accel_get_bw(data, val, val2); 6348c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 6358c2ecf20Sopenharmony_ci return ret; 6368c2ecf20Sopenharmony_ci default: 6378c2ecf20Sopenharmony_ci return -EINVAL; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int bmc150_accel_write_raw(struct iio_dev *indio_dev, 6428c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 6438c2ecf20Sopenharmony_ci int val, int val2, long mask) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 6468c2ecf20Sopenharmony_ci int ret; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci switch (mask) { 6498c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 6508c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 6518c2ecf20Sopenharmony_ci ret = bmc150_accel_set_bw(data, val, val2); 6528c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 6538c2ecf20Sopenharmony_ci break; 6548c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 6558c2ecf20Sopenharmony_ci if (val) 6568c2ecf20Sopenharmony_ci return -EINVAL; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 6598c2ecf20Sopenharmony_ci ret = bmc150_accel_set_scale(data, val2); 6608c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 6618c2ecf20Sopenharmony_ci return ret; 6628c2ecf20Sopenharmony_ci default: 6638c2ecf20Sopenharmony_ci ret = -EINVAL; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci return ret; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic int bmc150_accel_read_event(struct iio_dev *indio_dev, 6708c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 6718c2ecf20Sopenharmony_ci enum iio_event_type type, 6728c2ecf20Sopenharmony_ci enum iio_event_direction dir, 6738c2ecf20Sopenharmony_ci enum iio_event_info info, 6748c2ecf20Sopenharmony_ci int *val, int *val2) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci *val2 = 0; 6798c2ecf20Sopenharmony_ci switch (info) { 6808c2ecf20Sopenharmony_ci case IIO_EV_INFO_VALUE: 6818c2ecf20Sopenharmony_ci *val = data->slope_thres; 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci case IIO_EV_INFO_PERIOD: 6848c2ecf20Sopenharmony_ci *val = data->slope_dur; 6858c2ecf20Sopenharmony_ci break; 6868c2ecf20Sopenharmony_ci default: 6878c2ecf20Sopenharmony_ci return -EINVAL; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return IIO_VAL_INT; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic int bmc150_accel_write_event(struct iio_dev *indio_dev, 6948c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 6958c2ecf20Sopenharmony_ci enum iio_event_type type, 6968c2ecf20Sopenharmony_ci enum iio_event_direction dir, 6978c2ecf20Sopenharmony_ci enum iio_event_info info, 6988c2ecf20Sopenharmony_ci int val, int val2) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (data->ev_enable_state) 7038c2ecf20Sopenharmony_ci return -EBUSY; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci switch (info) { 7068c2ecf20Sopenharmony_ci case IIO_EV_INFO_VALUE: 7078c2ecf20Sopenharmony_ci data->slope_thres = val & BMC150_ACCEL_SLOPE_THRES_MASK; 7088c2ecf20Sopenharmony_ci break; 7098c2ecf20Sopenharmony_ci case IIO_EV_INFO_PERIOD: 7108c2ecf20Sopenharmony_ci data->slope_dur = val & BMC150_ACCEL_SLOPE_DUR_MASK; 7118c2ecf20Sopenharmony_ci break; 7128c2ecf20Sopenharmony_ci default: 7138c2ecf20Sopenharmony_ci return -EINVAL; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci return 0; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic int bmc150_accel_read_event_config(struct iio_dev *indio_dev, 7208c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 7218c2ecf20Sopenharmony_ci enum iio_event_type type, 7228c2ecf20Sopenharmony_ci enum iio_event_direction dir) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return data->ev_enable_state; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic int bmc150_accel_write_event_config(struct iio_dev *indio_dev, 7308c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 7318c2ecf20Sopenharmony_ci enum iio_event_type type, 7328c2ecf20Sopenharmony_ci enum iio_event_direction dir, 7338c2ecf20Sopenharmony_ci int state) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 7368c2ecf20Sopenharmony_ci int ret; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (state == data->ev_enable_state) 7398c2ecf20Sopenharmony_ci return 0; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_ANY_MOTION, 7448c2ecf20Sopenharmony_ci state); 7458c2ecf20Sopenharmony_ci if (ret < 0) { 7468c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 7478c2ecf20Sopenharmony_ci return ret; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci data->ev_enable_state = state; 7518c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci return 0; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic int bmc150_accel_validate_trigger(struct iio_dev *indio_dev, 7578c2ecf20Sopenharmony_ci struct iio_trigger *trig) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 7608c2ecf20Sopenharmony_ci int i; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { 7638c2ecf20Sopenharmony_ci if (data->triggers[i].indio_trig == trig) 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci return -EINVAL; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic ssize_t bmc150_accel_get_fifo_watermark(struct device *dev, 7718c2ecf20Sopenharmony_ci struct device_attribute *attr, 7728c2ecf20Sopenharmony_ci char *buf) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 7758c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 7768c2ecf20Sopenharmony_ci int wm; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 7798c2ecf20Sopenharmony_ci wm = data->watermark; 7808c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", wm); 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic ssize_t bmc150_accel_get_fifo_state(struct device *dev, 7868c2ecf20Sopenharmony_ci struct device_attribute *attr, 7878c2ecf20Sopenharmony_ci char *buf) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 7908c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 7918c2ecf20Sopenharmony_ci bool state; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 7948c2ecf20Sopenharmony_ci state = data->fifo_mode; 7958c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", state); 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic const struct iio_mount_matrix * 8018c2ecf20Sopenharmony_cibmc150_accel_get_mount_matrix(const struct iio_dev *indio_dev, 8028c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return &data->orientation; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info bmc150_accel_ext_info[] = { 8108c2ecf20Sopenharmony_ci IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_accel_get_mount_matrix), 8118c2ecf20Sopenharmony_ci { } 8128c2ecf20Sopenharmony_ci}; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR(hwfifo_watermark_min, "1"); 8158c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR(hwfifo_watermark_max, 8168c2ecf20Sopenharmony_ci __stringify(BMC150_ACCEL_FIFO_LENGTH)); 8178c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO, 8188c2ecf20Sopenharmony_ci bmc150_accel_get_fifo_state, NULL, 0); 8198c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO, 8208c2ecf20Sopenharmony_ci bmc150_accel_get_fifo_watermark, NULL, 0); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic const struct attribute *bmc150_accel_fifo_attributes[] = { 8238c2ecf20Sopenharmony_ci &iio_const_attr_hwfifo_watermark_min.dev_attr.attr, 8248c2ecf20Sopenharmony_ci &iio_const_attr_hwfifo_watermark_max.dev_attr.attr, 8258c2ecf20Sopenharmony_ci &iio_dev_attr_hwfifo_watermark.dev_attr.attr, 8268c2ecf20Sopenharmony_ci &iio_dev_attr_hwfifo_enabled.dev_attr.attr, 8278c2ecf20Sopenharmony_ci NULL, 8288c2ecf20Sopenharmony_ci}; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (val > BMC150_ACCEL_FIFO_LENGTH) 8358c2ecf20Sopenharmony_ci val = BMC150_ACCEL_FIFO_LENGTH; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 8388c2ecf20Sopenharmony_ci data->watermark = val; 8398c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci return 0; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci/* 8458c2ecf20Sopenharmony_ci * We must read at least one full frame in one burst, otherwise the rest of the 8468c2ecf20Sopenharmony_ci * frame data is discarded. 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_cistatic int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data, 8498c2ecf20Sopenharmony_ci char *buffer, int samples) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 8528c2ecf20Sopenharmony_ci int sample_length = 3 * 2; 8538c2ecf20Sopenharmony_ci int ret; 8548c2ecf20Sopenharmony_ci int total_length = samples * sample_length; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA, 8578c2ecf20Sopenharmony_ci buffer, total_length); 8588c2ecf20Sopenharmony_ci if (ret) 8598c2ecf20Sopenharmony_ci dev_err(dev, 8608c2ecf20Sopenharmony_ci "Error transferring data from fifo: %d\n", ret); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci return ret; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, 8668c2ecf20Sopenharmony_ci unsigned samples, bool irq) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 8698c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 8708c2ecf20Sopenharmony_ci int ret, i; 8718c2ecf20Sopenharmony_ci u8 count; 8728c2ecf20Sopenharmony_ci u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3]; 8738c2ecf20Sopenharmony_ci int64_t tstamp; 8748c2ecf20Sopenharmony_ci uint64_t sample_period; 8758c2ecf20Sopenharmony_ci unsigned int val; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_ACCEL_REG_FIFO_STATUS, &val); 8788c2ecf20Sopenharmony_ci if (ret < 0) { 8798c2ecf20Sopenharmony_ci dev_err(dev, "Error reading reg_fifo_status\n"); 8808c2ecf20Sopenharmony_ci return ret; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci count = val & 0x7F; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (!count) 8868c2ecf20Sopenharmony_ci return 0; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* 8898c2ecf20Sopenharmony_ci * If we getting called from IRQ handler we know the stored timestamp is 8908c2ecf20Sopenharmony_ci * fairly accurate for the last stored sample. Otherwise, if we are 8918c2ecf20Sopenharmony_ci * called as a result of a read operation from userspace and hence 8928c2ecf20Sopenharmony_ci * before the watermark interrupt was triggered, take a timestamp 8938c2ecf20Sopenharmony_ci * now. We can fall anywhere in between two samples so the error in this 8948c2ecf20Sopenharmony_ci * case is at most one sample period. 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_ci if (!irq) { 8978c2ecf20Sopenharmony_ci data->old_timestamp = data->timestamp; 8988c2ecf20Sopenharmony_ci data->timestamp = iio_get_time_ns(indio_dev); 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* 9028c2ecf20Sopenharmony_ci * Approximate timestamps for each of the sample based on the sampling 9038c2ecf20Sopenharmony_ci * frequency, timestamp for last sample and number of samples. 9048c2ecf20Sopenharmony_ci * 9058c2ecf20Sopenharmony_ci * Note that we can't use the current bandwidth settings to compute the 9068c2ecf20Sopenharmony_ci * sample period because the sample rate varies with the device 9078c2ecf20Sopenharmony_ci * (e.g. between 31.70ms to 32.20ms for a bandwidth of 15.63HZ). That 9088c2ecf20Sopenharmony_ci * small variation adds when we store a large number of samples and 9098c2ecf20Sopenharmony_ci * creates significant jitter between the last and first samples in 9108c2ecf20Sopenharmony_ci * different batches (e.g. 32ms vs 21ms). 9118c2ecf20Sopenharmony_ci * 9128c2ecf20Sopenharmony_ci * To avoid this issue we compute the actual sample period ourselves 9138c2ecf20Sopenharmony_ci * based on the timestamp delta between the last two flush operations. 9148c2ecf20Sopenharmony_ci */ 9158c2ecf20Sopenharmony_ci sample_period = (data->timestamp - data->old_timestamp); 9168c2ecf20Sopenharmony_ci do_div(sample_period, count); 9178c2ecf20Sopenharmony_ci tstamp = data->timestamp - (count - 1) * sample_period; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (samples && count > samples) 9208c2ecf20Sopenharmony_ci count = samples; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count); 9238c2ecf20Sopenharmony_ci if (ret) 9248c2ecf20Sopenharmony_ci return ret; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* 9278c2ecf20Sopenharmony_ci * Ideally we want the IIO core to handle the demux when running in fifo 9288c2ecf20Sopenharmony_ci * mode but not when running in triggered buffer mode. Unfortunately 9298c2ecf20Sopenharmony_ci * this does not seem to be possible, so stick with driver demux for 9308c2ecf20Sopenharmony_ci * now. 9318c2ecf20Sopenharmony_ci */ 9328c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 9338c2ecf20Sopenharmony_ci int j, bit; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci j = 0; 9368c2ecf20Sopenharmony_ci for_each_set_bit(bit, indio_dev->active_scan_mask, 9378c2ecf20Sopenharmony_ci indio_dev->masklength) 9388c2ecf20Sopenharmony_ci memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit], 9398c2ecf20Sopenharmony_ci sizeof(data->scan.channels[0])); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, 9428c2ecf20Sopenharmony_ci tstamp); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci tstamp += sample_period; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return count; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic int bmc150_accel_fifo_flush(struct iio_dev *indio_dev, unsigned samples) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 9538c2ecf20Sopenharmony_ci int ret; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 9568c2ecf20Sopenharmony_ci ret = __bmc150_accel_fifo_flush(indio_dev, samples, false); 9578c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci return ret; 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR_SAMP_FREQ_AVAIL( 9638c2ecf20Sopenharmony_ci "15.620000 31.260000 62.50000 125 250 500 1000 2000"); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic struct attribute *bmc150_accel_attributes[] = { 9668c2ecf20Sopenharmony_ci &iio_const_attr_sampling_frequency_available.dev_attr.attr, 9678c2ecf20Sopenharmony_ci NULL, 9688c2ecf20Sopenharmony_ci}; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic const struct attribute_group bmc150_accel_attrs_group = { 9718c2ecf20Sopenharmony_ci .attrs = bmc150_accel_attributes, 9728c2ecf20Sopenharmony_ci}; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic const struct iio_event_spec bmc150_accel_event = { 9758c2ecf20Sopenharmony_ci .type = IIO_EV_TYPE_ROC, 9768c2ecf20Sopenharmony_ci .dir = IIO_EV_DIR_EITHER, 9778c2ecf20Sopenharmony_ci .mask_separate = BIT(IIO_EV_INFO_VALUE) | 9788c2ecf20Sopenharmony_ci BIT(IIO_EV_INFO_ENABLE) | 9798c2ecf20Sopenharmony_ci BIT(IIO_EV_INFO_PERIOD) 9808c2ecf20Sopenharmony_ci}; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci#define BMC150_ACCEL_CHANNEL(_axis, bits) { \ 9838c2ecf20Sopenharmony_ci .type = IIO_ACCEL, \ 9848c2ecf20Sopenharmony_ci .modified = 1, \ 9858c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_##_axis, \ 9868c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 9878c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 9888c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 9898c2ecf20Sopenharmony_ci .scan_index = AXIS_##_axis, \ 9908c2ecf20Sopenharmony_ci .scan_type = { \ 9918c2ecf20Sopenharmony_ci .sign = 's', \ 9928c2ecf20Sopenharmony_ci .realbits = (bits), \ 9938c2ecf20Sopenharmony_ci .storagebits = 16, \ 9948c2ecf20Sopenharmony_ci .shift = 16 - (bits), \ 9958c2ecf20Sopenharmony_ci .endianness = IIO_LE, \ 9968c2ecf20Sopenharmony_ci }, \ 9978c2ecf20Sopenharmony_ci .ext_info = bmc150_accel_ext_info, \ 9988c2ecf20Sopenharmony_ci .event_spec = &bmc150_accel_event, \ 9998c2ecf20Sopenharmony_ci .num_event_specs = 1 \ 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci#define BMC150_ACCEL_CHANNELS(bits) { \ 10038c2ecf20Sopenharmony_ci { \ 10048c2ecf20Sopenharmony_ci .type = IIO_TEMP, \ 10058c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 10068c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | \ 10078c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET), \ 10088c2ecf20Sopenharmony_ci .scan_index = -1, \ 10098c2ecf20Sopenharmony_ci }, \ 10108c2ecf20Sopenharmony_ci BMC150_ACCEL_CHANNEL(X, bits), \ 10118c2ecf20Sopenharmony_ci BMC150_ACCEL_CHANNEL(Y, bits), \ 10128c2ecf20Sopenharmony_ci BMC150_ACCEL_CHANNEL(Z, bits), \ 10138c2ecf20Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(3), \ 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_cistatic const struct iio_chan_spec bma222e_accel_channels[] = 10178c2ecf20Sopenharmony_ci BMC150_ACCEL_CHANNELS(8); 10188c2ecf20Sopenharmony_cistatic const struct iio_chan_spec bma250e_accel_channels[] = 10198c2ecf20Sopenharmony_ci BMC150_ACCEL_CHANNELS(10); 10208c2ecf20Sopenharmony_cistatic const struct iio_chan_spec bmc150_accel_channels[] = 10218c2ecf20Sopenharmony_ci BMC150_ACCEL_CHANNELS(12); 10228c2ecf20Sopenharmony_cistatic const struct iio_chan_spec bma280_accel_channels[] = 10238c2ecf20Sopenharmony_ci BMC150_ACCEL_CHANNELS(14); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { 10268c2ecf20Sopenharmony_ci [bmc150] = { 10278c2ecf20Sopenharmony_ci .name = "BMC150A", 10288c2ecf20Sopenharmony_ci .chip_id = 0xFA, 10298c2ecf20Sopenharmony_ci .channels = bmc150_accel_channels, 10308c2ecf20Sopenharmony_ci .num_channels = ARRAY_SIZE(bmc150_accel_channels), 10318c2ecf20Sopenharmony_ci .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, 10328c2ecf20Sopenharmony_ci {19122, BMC150_ACCEL_DEF_RANGE_4G}, 10338c2ecf20Sopenharmony_ci {38344, BMC150_ACCEL_DEF_RANGE_8G}, 10348c2ecf20Sopenharmony_ci {76590, BMC150_ACCEL_DEF_RANGE_16G} }, 10358c2ecf20Sopenharmony_ci }, 10368c2ecf20Sopenharmony_ci [bmi055] = { 10378c2ecf20Sopenharmony_ci .name = "BMI055A", 10388c2ecf20Sopenharmony_ci .chip_id = 0xFA, 10398c2ecf20Sopenharmony_ci .channels = bmc150_accel_channels, 10408c2ecf20Sopenharmony_ci .num_channels = ARRAY_SIZE(bmc150_accel_channels), 10418c2ecf20Sopenharmony_ci .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, 10428c2ecf20Sopenharmony_ci {19122, BMC150_ACCEL_DEF_RANGE_4G}, 10438c2ecf20Sopenharmony_ci {38344, BMC150_ACCEL_DEF_RANGE_8G}, 10448c2ecf20Sopenharmony_ci {76590, BMC150_ACCEL_DEF_RANGE_16G} }, 10458c2ecf20Sopenharmony_ci }, 10468c2ecf20Sopenharmony_ci [bma255] = { 10478c2ecf20Sopenharmony_ci .name = "BMA0255", 10488c2ecf20Sopenharmony_ci .chip_id = 0xFA, 10498c2ecf20Sopenharmony_ci .channels = bmc150_accel_channels, 10508c2ecf20Sopenharmony_ci .num_channels = ARRAY_SIZE(bmc150_accel_channels), 10518c2ecf20Sopenharmony_ci .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, 10528c2ecf20Sopenharmony_ci {19122, BMC150_ACCEL_DEF_RANGE_4G}, 10538c2ecf20Sopenharmony_ci {38344, BMC150_ACCEL_DEF_RANGE_8G}, 10548c2ecf20Sopenharmony_ci {76590, BMC150_ACCEL_DEF_RANGE_16G} }, 10558c2ecf20Sopenharmony_ci }, 10568c2ecf20Sopenharmony_ci [bma250e] = { 10578c2ecf20Sopenharmony_ci .name = "BMA250E", 10588c2ecf20Sopenharmony_ci .chip_id = 0xF9, 10598c2ecf20Sopenharmony_ci .channels = bma250e_accel_channels, 10608c2ecf20Sopenharmony_ci .num_channels = ARRAY_SIZE(bma250e_accel_channels), 10618c2ecf20Sopenharmony_ci .scale_table = { {38344, BMC150_ACCEL_DEF_RANGE_2G}, 10628c2ecf20Sopenharmony_ci {76590, BMC150_ACCEL_DEF_RANGE_4G}, 10638c2ecf20Sopenharmony_ci {153277, BMC150_ACCEL_DEF_RANGE_8G}, 10648c2ecf20Sopenharmony_ci {306457, BMC150_ACCEL_DEF_RANGE_16G} }, 10658c2ecf20Sopenharmony_ci }, 10668c2ecf20Sopenharmony_ci [bma222e] = { 10678c2ecf20Sopenharmony_ci .name = "BMA222E", 10688c2ecf20Sopenharmony_ci .chip_id = 0xF8, 10698c2ecf20Sopenharmony_ci .channels = bma222e_accel_channels, 10708c2ecf20Sopenharmony_ci .num_channels = ARRAY_SIZE(bma222e_accel_channels), 10718c2ecf20Sopenharmony_ci .scale_table = { {153277, BMC150_ACCEL_DEF_RANGE_2G}, 10728c2ecf20Sopenharmony_ci {306457, BMC150_ACCEL_DEF_RANGE_4G}, 10738c2ecf20Sopenharmony_ci {612915, BMC150_ACCEL_DEF_RANGE_8G}, 10748c2ecf20Sopenharmony_ci {1225831, BMC150_ACCEL_DEF_RANGE_16G} }, 10758c2ecf20Sopenharmony_ci }, 10768c2ecf20Sopenharmony_ci [bma280] = { 10778c2ecf20Sopenharmony_ci .name = "BMA0280", 10788c2ecf20Sopenharmony_ci .chip_id = 0xFB, 10798c2ecf20Sopenharmony_ci .channels = bma280_accel_channels, 10808c2ecf20Sopenharmony_ci .num_channels = ARRAY_SIZE(bma280_accel_channels), 10818c2ecf20Sopenharmony_ci .scale_table = { {2392, BMC150_ACCEL_DEF_RANGE_2G}, 10828c2ecf20Sopenharmony_ci {4785, BMC150_ACCEL_DEF_RANGE_4G}, 10838c2ecf20Sopenharmony_ci {9581, BMC150_ACCEL_DEF_RANGE_8G}, 10848c2ecf20Sopenharmony_ci {19152, BMC150_ACCEL_DEF_RANGE_16G} }, 10858c2ecf20Sopenharmony_ci }, 10868c2ecf20Sopenharmony_ci}; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic const struct iio_info bmc150_accel_info = { 10898c2ecf20Sopenharmony_ci .attrs = &bmc150_accel_attrs_group, 10908c2ecf20Sopenharmony_ci .read_raw = bmc150_accel_read_raw, 10918c2ecf20Sopenharmony_ci .write_raw = bmc150_accel_write_raw, 10928c2ecf20Sopenharmony_ci .read_event_value = bmc150_accel_read_event, 10938c2ecf20Sopenharmony_ci .write_event_value = bmc150_accel_write_event, 10948c2ecf20Sopenharmony_ci .write_event_config = bmc150_accel_write_event_config, 10958c2ecf20Sopenharmony_ci .read_event_config = bmc150_accel_read_event_config, 10968c2ecf20Sopenharmony_ci}; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic const struct iio_info bmc150_accel_info_fifo = { 10998c2ecf20Sopenharmony_ci .attrs = &bmc150_accel_attrs_group, 11008c2ecf20Sopenharmony_ci .read_raw = bmc150_accel_read_raw, 11018c2ecf20Sopenharmony_ci .write_raw = bmc150_accel_write_raw, 11028c2ecf20Sopenharmony_ci .read_event_value = bmc150_accel_read_event, 11038c2ecf20Sopenharmony_ci .write_event_value = bmc150_accel_write_event, 11048c2ecf20Sopenharmony_ci .write_event_config = bmc150_accel_write_event_config, 11058c2ecf20Sopenharmony_ci .read_event_config = bmc150_accel_read_event_config, 11068c2ecf20Sopenharmony_ci .validate_trigger = bmc150_accel_validate_trigger, 11078c2ecf20Sopenharmony_ci .hwfifo_set_watermark = bmc150_accel_set_watermark, 11088c2ecf20Sopenharmony_ci .hwfifo_flush_to_buffer = bmc150_accel_fifo_flush, 11098c2ecf20Sopenharmony_ci}; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic const unsigned long bmc150_accel_scan_masks[] = { 11128c2ecf20Sopenharmony_ci BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), 11138c2ecf20Sopenharmony_ci 0}; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic irqreturn_t bmc150_accel_trigger_handler(int irq, void *p) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci struct iio_poll_func *pf = p; 11188c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = pf->indio_dev; 11198c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 11208c2ecf20Sopenharmony_ci int ret; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 11238c2ecf20Sopenharmony_ci ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_REG_XOUT_L, 11248c2ecf20Sopenharmony_ci data->buffer, AXIS_MAX * 2); 11258c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 11268c2ecf20Sopenharmony_ci if (ret < 0) 11278c2ecf20Sopenharmony_ci goto err_read; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, 11308c2ecf20Sopenharmony_ci pf->timestamp); 11318c2ecf20Sopenharmony_cierr_read: 11328c2ecf20Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic int bmc150_accel_trig_try_reen(struct iio_trigger *trig) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig); 11408c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = t->data; 11418c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 11428c2ecf20Sopenharmony_ci int ret; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* new data interrupts don't need ack */ 11458c2ecf20Sopenharmony_ci if (t == &t->data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY]) 11468c2ecf20Sopenharmony_ci return 0; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 11498c2ecf20Sopenharmony_ci /* clear any latched interrupt */ 11508c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, 11518c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_MODE_LATCH_INT | 11528c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_MODE_LATCH_RESET); 11538c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 11548c2ecf20Sopenharmony_ci if (ret < 0) { 11558c2ecf20Sopenharmony_ci dev_err(dev, "Error writing reg_int_rst_latch\n"); 11568c2ecf20Sopenharmony_ci return ret; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci return 0; 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_cistatic int bmc150_accel_trigger_set_state(struct iio_trigger *trig, 11638c2ecf20Sopenharmony_ci bool state) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig); 11668c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = t->data; 11678c2ecf20Sopenharmony_ci int ret; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (t->enabled == state) { 11728c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 11738c2ecf20Sopenharmony_ci return 0; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if (t->setup) { 11778c2ecf20Sopenharmony_ci ret = t->setup(t, state); 11788c2ecf20Sopenharmony_ci if (ret < 0) { 11798c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 11808c2ecf20Sopenharmony_ci return ret; 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci ret = bmc150_accel_set_interrupt(data, t->intr, state); 11858c2ecf20Sopenharmony_ci if (ret < 0) { 11868c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 11878c2ecf20Sopenharmony_ci return ret; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci t->enabled = state; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci return ret; 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_cistatic const struct iio_trigger_ops bmc150_accel_trigger_ops = { 11988c2ecf20Sopenharmony_ci .set_trigger_state = bmc150_accel_trigger_set_state, 11998c2ecf20Sopenharmony_ci .try_reenable = bmc150_accel_trig_try_reen, 12008c2ecf20Sopenharmony_ci}; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 12058c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 12068c2ecf20Sopenharmony_ci int dir; 12078c2ecf20Sopenharmony_ci int ret; 12088c2ecf20Sopenharmony_ci unsigned int val; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_ACCEL_REG_INT_STATUS_2, &val); 12118c2ecf20Sopenharmony_ci if (ret < 0) { 12128c2ecf20Sopenharmony_ci dev_err(dev, "Error reading reg_int_status_2\n"); 12138c2ecf20Sopenharmony_ci return ret; 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (val & BMC150_ACCEL_ANY_MOTION_BIT_SIGN) 12178c2ecf20Sopenharmony_ci dir = IIO_EV_DIR_FALLING; 12188c2ecf20Sopenharmony_ci else 12198c2ecf20Sopenharmony_ci dir = IIO_EV_DIR_RISING; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (val & BMC150_ACCEL_ANY_MOTION_BIT_X) 12228c2ecf20Sopenharmony_ci iio_push_event(indio_dev, 12238c2ecf20Sopenharmony_ci IIO_MOD_EVENT_CODE(IIO_ACCEL, 12248c2ecf20Sopenharmony_ci 0, 12258c2ecf20Sopenharmony_ci IIO_MOD_X, 12268c2ecf20Sopenharmony_ci IIO_EV_TYPE_ROC, 12278c2ecf20Sopenharmony_ci dir), 12288c2ecf20Sopenharmony_ci data->timestamp); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (val & BMC150_ACCEL_ANY_MOTION_BIT_Y) 12318c2ecf20Sopenharmony_ci iio_push_event(indio_dev, 12328c2ecf20Sopenharmony_ci IIO_MOD_EVENT_CODE(IIO_ACCEL, 12338c2ecf20Sopenharmony_ci 0, 12348c2ecf20Sopenharmony_ci IIO_MOD_Y, 12358c2ecf20Sopenharmony_ci IIO_EV_TYPE_ROC, 12368c2ecf20Sopenharmony_ci dir), 12378c2ecf20Sopenharmony_ci data->timestamp); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (val & BMC150_ACCEL_ANY_MOTION_BIT_Z) 12408c2ecf20Sopenharmony_ci iio_push_event(indio_dev, 12418c2ecf20Sopenharmony_ci IIO_MOD_EVENT_CODE(IIO_ACCEL, 12428c2ecf20Sopenharmony_ci 0, 12438c2ecf20Sopenharmony_ci IIO_MOD_Z, 12448c2ecf20Sopenharmony_ci IIO_EV_TYPE_ROC, 12458c2ecf20Sopenharmony_ci dir), 12468c2ecf20Sopenharmony_ci data->timestamp); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci return ret; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_cistatic irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = private; 12548c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 12558c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 12568c2ecf20Sopenharmony_ci bool ack = false; 12578c2ecf20Sopenharmony_ci int ret; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (data->fifo_mode) { 12628c2ecf20Sopenharmony_ci ret = __bmc150_accel_fifo_flush(indio_dev, 12638c2ecf20Sopenharmony_ci BMC150_ACCEL_FIFO_LENGTH, true); 12648c2ecf20Sopenharmony_ci if (ret > 0) 12658c2ecf20Sopenharmony_ci ack = true; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (data->ev_enable_state) { 12698c2ecf20Sopenharmony_ci ret = bmc150_accel_handle_roc_event(indio_dev); 12708c2ecf20Sopenharmony_ci if (ret > 0) 12718c2ecf20Sopenharmony_ci ack = true; 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci if (ack) { 12758c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, 12768c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_MODE_LATCH_INT | 12778c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_MODE_LATCH_RESET); 12788c2ecf20Sopenharmony_ci if (ret) 12798c2ecf20Sopenharmony_ci dev_err(dev, "Error writing reg_int_rst_latch\n"); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 12828c2ecf20Sopenharmony_ci } else { 12838c2ecf20Sopenharmony_ci ret = IRQ_NONE; 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci return ret; 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistatic irqreturn_t bmc150_accel_irq_handler(int irq, void *private) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = private; 12948c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 12958c2ecf20Sopenharmony_ci bool ack = false; 12968c2ecf20Sopenharmony_ci int i; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci data->old_timestamp = data->timestamp; 12998c2ecf20Sopenharmony_ci data->timestamp = iio_get_time_ns(indio_dev); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { 13028c2ecf20Sopenharmony_ci if (data->triggers[i].enabled) { 13038c2ecf20Sopenharmony_ci iio_trigger_poll(data->triggers[i].indio_trig); 13048c2ecf20Sopenharmony_ci ack = true; 13058c2ecf20Sopenharmony_ci break; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (data->ev_enable_state || data->fifo_mode) 13108c2ecf20Sopenharmony_ci return IRQ_WAKE_THREAD; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (ack) 13138c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci return IRQ_NONE; 13168c2ecf20Sopenharmony_ci} 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic const struct { 13198c2ecf20Sopenharmony_ci int intr; 13208c2ecf20Sopenharmony_ci const char *name; 13218c2ecf20Sopenharmony_ci int (*setup)(struct bmc150_accel_trigger *t, bool state); 13228c2ecf20Sopenharmony_ci} bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = { 13238c2ecf20Sopenharmony_ci { 13248c2ecf20Sopenharmony_ci .intr = 0, 13258c2ecf20Sopenharmony_ci .name = "%s-dev%d", 13268c2ecf20Sopenharmony_ci }, 13278c2ecf20Sopenharmony_ci { 13288c2ecf20Sopenharmony_ci .intr = 1, 13298c2ecf20Sopenharmony_ci .name = "%s-any-motion-dev%d", 13308c2ecf20Sopenharmony_ci .setup = bmc150_accel_any_motion_setup, 13318c2ecf20Sopenharmony_ci }, 13328c2ecf20Sopenharmony_ci}; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_cistatic void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data, 13358c2ecf20Sopenharmony_ci int from) 13368c2ecf20Sopenharmony_ci{ 13378c2ecf20Sopenharmony_ci int i; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci for (i = from; i >= 0; i--) { 13408c2ecf20Sopenharmony_ci if (data->triggers[i].indio_trig) { 13418c2ecf20Sopenharmony_ci iio_trigger_unregister(data->triggers[i].indio_trig); 13428c2ecf20Sopenharmony_ci data->triggers[i].indio_trig = NULL; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_cistatic int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, 13488c2ecf20Sopenharmony_ci struct bmc150_accel_data *data) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 13518c2ecf20Sopenharmony_ci int i, ret; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { 13548c2ecf20Sopenharmony_ci struct bmc150_accel_trigger *t = &data->triggers[i]; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci t->indio_trig = devm_iio_trigger_alloc(dev, 13578c2ecf20Sopenharmony_ci bmc150_accel_triggers[i].name, 13588c2ecf20Sopenharmony_ci indio_dev->name, 13598c2ecf20Sopenharmony_ci indio_dev->id); 13608c2ecf20Sopenharmony_ci if (!t->indio_trig) { 13618c2ecf20Sopenharmony_ci ret = -ENOMEM; 13628c2ecf20Sopenharmony_ci break; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci t->indio_trig->dev.parent = dev; 13668c2ecf20Sopenharmony_ci t->indio_trig->ops = &bmc150_accel_trigger_ops; 13678c2ecf20Sopenharmony_ci t->intr = bmc150_accel_triggers[i].intr; 13688c2ecf20Sopenharmony_ci t->data = data; 13698c2ecf20Sopenharmony_ci t->setup = bmc150_accel_triggers[i].setup; 13708c2ecf20Sopenharmony_ci iio_trigger_set_drvdata(t->indio_trig, t); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci ret = iio_trigger_register(t->indio_trig); 13738c2ecf20Sopenharmony_ci if (ret) 13748c2ecf20Sopenharmony_ci break; 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci if (ret) 13788c2ecf20Sopenharmony_ci bmc150_accel_unregister_triggers(data, i - 1); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci return ret; 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci#define BMC150_ACCEL_FIFO_MODE_STREAM 0x80 13848c2ecf20Sopenharmony_ci#define BMC150_ACCEL_FIFO_MODE_FIFO 0x40 13858c2ecf20Sopenharmony_ci#define BMC150_ACCEL_FIFO_MODE_BYPASS 0x00 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 13908c2ecf20Sopenharmony_ci u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1; 13918c2ecf20Sopenharmony_ci int ret; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, reg, data->fifo_mode); 13948c2ecf20Sopenharmony_ci if (ret < 0) { 13958c2ecf20Sopenharmony_ci dev_err(dev, "Error writing reg_fifo_config1\n"); 13968c2ecf20Sopenharmony_ci return ret; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (!data->fifo_mode) 14008c2ecf20Sopenharmony_ci return 0; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_ACCEL_REG_FIFO_CONFIG0, 14038c2ecf20Sopenharmony_ci data->watermark); 14048c2ecf20Sopenharmony_ci if (ret < 0) 14058c2ecf20Sopenharmony_ci dev_err(dev, "Error writing reg_fifo_config0\n"); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci return ret; 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic int bmc150_accel_buffer_preenable(struct iio_dev *indio_dev) 14118c2ecf20Sopenharmony_ci{ 14128c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci return bmc150_accel_set_power_state(data, true); 14158c2ecf20Sopenharmony_ci} 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_cistatic int bmc150_accel_buffer_postenable(struct iio_dev *indio_dev) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 14208c2ecf20Sopenharmony_ci int ret = 0; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) 14238c2ecf20Sopenharmony_ci return 0; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (!data->watermark) 14288c2ecf20Sopenharmony_ci goto out; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, 14318c2ecf20Sopenharmony_ci true); 14328c2ecf20Sopenharmony_ci if (ret) 14338c2ecf20Sopenharmony_ci goto out; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci data->fifo_mode = BMC150_ACCEL_FIFO_MODE_FIFO; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci ret = bmc150_accel_fifo_set_mode(data); 14388c2ecf20Sopenharmony_ci if (ret) { 14398c2ecf20Sopenharmony_ci data->fifo_mode = 0; 14408c2ecf20Sopenharmony_ci bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, 14418c2ecf20Sopenharmony_ci false); 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ciout: 14458c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci return ret; 14488c2ecf20Sopenharmony_ci} 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_cistatic int bmc150_accel_buffer_predisable(struct iio_dev *indio_dev) 14518c2ecf20Sopenharmony_ci{ 14528c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) 14558c2ecf20Sopenharmony_ci return 0; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (!data->fifo_mode) 14608c2ecf20Sopenharmony_ci goto out; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, false); 14638c2ecf20Sopenharmony_ci __bmc150_accel_fifo_flush(indio_dev, BMC150_ACCEL_FIFO_LENGTH, false); 14648c2ecf20Sopenharmony_ci data->fifo_mode = 0; 14658c2ecf20Sopenharmony_ci bmc150_accel_fifo_set_mode(data); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ciout: 14688c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci return 0; 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_cistatic int bmc150_accel_buffer_postdisable(struct iio_dev *indio_dev) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci return bmc150_accel_set_power_state(data, false); 14788c2ecf20Sopenharmony_ci} 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_cistatic const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { 14818c2ecf20Sopenharmony_ci .preenable = bmc150_accel_buffer_preenable, 14828c2ecf20Sopenharmony_ci .postenable = bmc150_accel_buffer_postenable, 14838c2ecf20Sopenharmony_ci .predisable = bmc150_accel_buffer_predisable, 14848c2ecf20Sopenharmony_ci .postdisable = bmc150_accel_buffer_postdisable, 14858c2ecf20Sopenharmony_ci}; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_cistatic int bmc150_accel_chip_init(struct bmc150_accel_data *data) 14888c2ecf20Sopenharmony_ci{ 14898c2ecf20Sopenharmony_ci struct device *dev = regmap_get_device(data->regmap); 14908c2ecf20Sopenharmony_ci int ret, i; 14918c2ecf20Sopenharmony_ci unsigned int val; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci /* 14948c2ecf20Sopenharmony_ci * Reset chip to get it in a known good state. A delay of 1.8ms after 14958c2ecf20Sopenharmony_ci * reset is required according to the data sheets of supported chips. 14968c2ecf20Sopenharmony_ci */ 14978c2ecf20Sopenharmony_ci regmap_write(data->regmap, BMC150_ACCEL_REG_RESET, 14988c2ecf20Sopenharmony_ci BMC150_ACCEL_RESET_VAL); 14998c2ecf20Sopenharmony_ci usleep_range(1800, 2500); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val); 15028c2ecf20Sopenharmony_ci if (ret < 0) { 15038c2ecf20Sopenharmony_ci dev_err(dev, "Error: Reading chip id\n"); 15048c2ecf20Sopenharmony_ci return ret; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci dev_dbg(dev, "Chip Id %x\n", val); 15088c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) { 15098c2ecf20Sopenharmony_ci if (bmc150_accel_chip_info_tbl[i].chip_id == val) { 15108c2ecf20Sopenharmony_ci data->chip_info = &bmc150_accel_chip_info_tbl[i]; 15118c2ecf20Sopenharmony_ci break; 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (!data->chip_info) { 15168c2ecf20Sopenharmony_ci dev_err(dev, "Invalid chip %x\n", val); 15178c2ecf20Sopenharmony_ci return -ENODEV; 15188c2ecf20Sopenharmony_ci } 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); 15218c2ecf20Sopenharmony_ci if (ret < 0) 15228c2ecf20Sopenharmony_ci return ret; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci /* Set Bandwidth */ 15258c2ecf20Sopenharmony_ci ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); 15268c2ecf20Sopenharmony_ci if (ret < 0) 15278c2ecf20Sopenharmony_ci return ret; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci /* Set Default Range */ 15308c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE, 15318c2ecf20Sopenharmony_ci BMC150_ACCEL_DEF_RANGE_4G); 15328c2ecf20Sopenharmony_ci if (ret < 0) { 15338c2ecf20Sopenharmony_ci dev_err(dev, "Error writing reg_pmu_range\n"); 15348c2ecf20Sopenharmony_ci return ret; 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci data->range = BMC150_ACCEL_DEF_RANGE_4G; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci /* Set default slope duration and thresholds */ 15408c2ecf20Sopenharmony_ci data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; 15418c2ecf20Sopenharmony_ci data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; 15428c2ecf20Sopenharmony_ci ret = bmc150_accel_update_slope(data); 15438c2ecf20Sopenharmony_ci if (ret < 0) 15448c2ecf20Sopenharmony_ci return ret; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci /* Set default as latched interrupts */ 15478c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, 15488c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_MODE_LATCH_INT | 15498c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_MODE_LATCH_RESET); 15508c2ecf20Sopenharmony_ci if (ret < 0) { 15518c2ecf20Sopenharmony_ci dev_err(dev, "Error writing reg_int_rst_latch\n"); 15528c2ecf20Sopenharmony_ci return ret; 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci return 0; 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ciint bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, 15598c2ecf20Sopenharmony_ci const char *name, bool block_supported) 15608c2ecf20Sopenharmony_ci{ 15618c2ecf20Sopenharmony_ci struct bmc150_accel_data *data; 15628c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 15638c2ecf20Sopenharmony_ci int ret; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 15668c2ecf20Sopenharmony_ci if (!indio_dev) 15678c2ecf20Sopenharmony_ci return -ENOMEM; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci data = iio_priv(indio_dev); 15708c2ecf20Sopenharmony_ci dev_set_drvdata(dev, indio_dev); 15718c2ecf20Sopenharmony_ci data->irq = irq; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci data->regmap = regmap; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci ret = iio_read_mount_matrix(dev, "mount-matrix", 15768c2ecf20Sopenharmony_ci &data->orientation); 15778c2ecf20Sopenharmony_ci if (ret) 15788c2ecf20Sopenharmony_ci return ret; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci ret = bmc150_accel_chip_init(data); 15818c2ecf20Sopenharmony_ci if (ret < 0) 15828c2ecf20Sopenharmony_ci return ret; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci mutex_init(&data->mutex); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci indio_dev->channels = data->chip_info->channels; 15878c2ecf20Sopenharmony_ci indio_dev->num_channels = data->chip_info->num_channels; 15888c2ecf20Sopenharmony_ci indio_dev->name = name ? name : data->chip_info->name; 15898c2ecf20Sopenharmony_ci indio_dev->available_scan_masks = bmc150_accel_scan_masks; 15908c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 15918c2ecf20Sopenharmony_ci indio_dev->info = &bmc150_accel_info; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci ret = iio_triggered_buffer_setup(indio_dev, 15948c2ecf20Sopenharmony_ci &iio_pollfunc_store_time, 15958c2ecf20Sopenharmony_ci bmc150_accel_trigger_handler, 15968c2ecf20Sopenharmony_ci &bmc150_accel_buffer_ops); 15978c2ecf20Sopenharmony_ci if (ret < 0) { 15988c2ecf20Sopenharmony_ci dev_err(dev, "Failed: iio triggered buffer setup\n"); 15998c2ecf20Sopenharmony_ci return ret; 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci if (data->irq > 0) { 16038c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq( 16048c2ecf20Sopenharmony_ci dev, data->irq, 16058c2ecf20Sopenharmony_ci bmc150_accel_irq_handler, 16068c2ecf20Sopenharmony_ci bmc150_accel_irq_thread_handler, 16078c2ecf20Sopenharmony_ci IRQF_TRIGGER_RISING, 16088c2ecf20Sopenharmony_ci BMC150_ACCEL_IRQ_NAME, 16098c2ecf20Sopenharmony_ci indio_dev); 16108c2ecf20Sopenharmony_ci if (ret) 16118c2ecf20Sopenharmony_ci goto err_buffer_cleanup; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci /* 16148c2ecf20Sopenharmony_ci * Set latched mode interrupt. While certain interrupts are 16158c2ecf20Sopenharmony_ci * non-latched regardless of this settings (e.g. new data) we 16168c2ecf20Sopenharmony_ci * want to use latch mode when we can to prevent interrupt 16178c2ecf20Sopenharmony_ci * flooding. 16188c2ecf20Sopenharmony_ci */ 16198c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, 16208c2ecf20Sopenharmony_ci BMC150_ACCEL_INT_MODE_LATCH_RESET); 16218c2ecf20Sopenharmony_ci if (ret < 0) { 16228c2ecf20Sopenharmony_ci dev_err(dev, "Error writing reg_int_rst_latch\n"); 16238c2ecf20Sopenharmony_ci goto err_buffer_cleanup; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci bmc150_accel_interrupts_setup(indio_dev, data); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci ret = bmc150_accel_triggers_setup(indio_dev, data); 16298c2ecf20Sopenharmony_ci if (ret) 16308c2ecf20Sopenharmony_ci goto err_buffer_cleanup; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci if (block_supported) { 16338c2ecf20Sopenharmony_ci indio_dev->modes |= INDIO_BUFFER_SOFTWARE; 16348c2ecf20Sopenharmony_ci indio_dev->info = &bmc150_accel_info_fifo; 16358c2ecf20Sopenharmony_ci iio_buffer_set_attrs(indio_dev->buffer, 16368c2ecf20Sopenharmony_ci bmc150_accel_fifo_attributes); 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci ret = pm_runtime_set_active(dev); 16418c2ecf20Sopenharmony_ci if (ret) 16428c2ecf20Sopenharmony_ci goto err_trigger_unregister; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 16458c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS); 16468c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 16498c2ecf20Sopenharmony_ci if (ret < 0) { 16508c2ecf20Sopenharmony_ci dev_err(dev, "Unable to register iio device\n"); 16518c2ecf20Sopenharmony_ci goto err_pm_cleanup; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci return 0; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cierr_pm_cleanup: 16578c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 16588c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 16598c2ecf20Sopenharmony_cierr_trigger_unregister: 16608c2ecf20Sopenharmony_ci bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1); 16618c2ecf20Sopenharmony_cierr_buffer_cleanup: 16628c2ecf20Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci return ret; 16658c2ecf20Sopenharmony_ci} 16668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bmc150_accel_core_probe); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ciint bmc150_accel_core_remove(struct device *dev) 16698c2ecf20Sopenharmony_ci{ 16708c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 16718c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 16768c2ecf20Sopenharmony_ci pm_runtime_set_suspended(dev); 16778c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1); 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 16848c2ecf20Sopenharmony_ci bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0); 16858c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci return 0; 16888c2ecf20Sopenharmony_ci} 16898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bmc150_accel_core_remove); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 16928c2ecf20Sopenharmony_cistatic int bmc150_accel_suspend(struct device *dev) 16938c2ecf20Sopenharmony_ci{ 16948c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 16958c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 16988c2ecf20Sopenharmony_ci bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); 16998c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci return 0; 17028c2ecf20Sopenharmony_ci} 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_cistatic int bmc150_accel_resume(struct device *dev) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 17078c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 17108c2ecf20Sopenharmony_ci bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); 17118c2ecf20Sopenharmony_ci bmc150_accel_fifo_set_mode(data); 17128c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci return 0; 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci#endif 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 17198c2ecf20Sopenharmony_cistatic int bmc150_accel_runtime_suspend(struct device *dev) 17208c2ecf20Sopenharmony_ci{ 17218c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 17228c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 17238c2ecf20Sopenharmony_ci int ret; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); 17268c2ecf20Sopenharmony_ci if (ret < 0) 17278c2ecf20Sopenharmony_ci return -EAGAIN; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci return 0; 17308c2ecf20Sopenharmony_ci} 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_cistatic int bmc150_accel_runtime_resume(struct device *dev) 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 17358c2ecf20Sopenharmony_ci struct bmc150_accel_data *data = iio_priv(indio_dev); 17368c2ecf20Sopenharmony_ci int ret; 17378c2ecf20Sopenharmony_ci int sleep_val; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); 17408c2ecf20Sopenharmony_ci if (ret < 0) 17418c2ecf20Sopenharmony_ci return ret; 17428c2ecf20Sopenharmony_ci ret = bmc150_accel_fifo_set_mode(data); 17438c2ecf20Sopenharmony_ci if (ret < 0) 17448c2ecf20Sopenharmony_ci return ret; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci sleep_val = bmc150_accel_get_startup_times(data); 17478c2ecf20Sopenharmony_ci if (sleep_val < 20) 17488c2ecf20Sopenharmony_ci usleep_range(sleep_val * 1000, 20000); 17498c2ecf20Sopenharmony_ci else 17508c2ecf20Sopenharmony_ci msleep_interruptible(sleep_val); 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci return 0; 17538c2ecf20Sopenharmony_ci} 17548c2ecf20Sopenharmony_ci#endif 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ciconst struct dev_pm_ops bmc150_accel_pm_ops = { 17578c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume) 17588c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, 17598c2ecf20Sopenharmony_ci bmc150_accel_runtime_resume, NULL) 17608c2ecf20Sopenharmony_ci}; 17618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bmc150_accel_pm_ops); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ciMODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 17648c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 17658c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BMC150 accelerometer driver"); 1766