18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 3-axis accelerometer driver for MXC4005XC Memsic sensor 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014, Intel Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/i2c.h> 108c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 118c2ecf20Sopenharmony_ci#include <linux/acpi.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 148c2ecf20Sopenharmony_ci#include <linux/iio/trigger.h> 158c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h> 168c2ecf20Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 178c2ecf20Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define MXC4005_DRV_NAME "mxc4005" 208c2ecf20Sopenharmony_ci#define MXC4005_IRQ_NAME "mxc4005_event" 218c2ecf20Sopenharmony_ci#define MXC4005_REGMAP_NAME "mxc4005_regmap" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define MXC4005_REG_XOUT_UPPER 0x03 248c2ecf20Sopenharmony_ci#define MXC4005_REG_XOUT_LOWER 0x04 258c2ecf20Sopenharmony_ci#define MXC4005_REG_YOUT_UPPER 0x05 268c2ecf20Sopenharmony_ci#define MXC4005_REG_YOUT_LOWER 0x06 278c2ecf20Sopenharmony_ci#define MXC4005_REG_ZOUT_UPPER 0x07 288c2ecf20Sopenharmony_ci#define MXC4005_REG_ZOUT_LOWER 0x08 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define MXC4005_REG_INT_MASK1 0x0B 318c2ecf20Sopenharmony_ci#define MXC4005_REG_INT_MASK1_BIT_DRDYE 0x01 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define MXC4005_REG_INT_CLR1 0x01 348c2ecf20Sopenharmony_ci#define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define MXC4005_REG_CONTROL 0x0D 378c2ecf20Sopenharmony_ci#define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) 388c2ecf20Sopenharmony_ci#define MXC4005_CONTROL_FSR_SHIFT 5 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define MXC4005_REG_DEVICE_ID 0x0E 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cienum mxc4005_axis { 438c2ecf20Sopenharmony_ci AXIS_X, 448c2ecf20Sopenharmony_ci AXIS_Y, 458c2ecf20Sopenharmony_ci AXIS_Z, 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cienum mxc4005_range { 498c2ecf20Sopenharmony_ci MXC4005_RANGE_2G, 508c2ecf20Sopenharmony_ci MXC4005_RANGE_4G, 518c2ecf20Sopenharmony_ci MXC4005_RANGE_8G, 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistruct mxc4005_data { 558c2ecf20Sopenharmony_ci struct device *dev; 568c2ecf20Sopenharmony_ci struct mutex mutex; 578c2ecf20Sopenharmony_ci struct regmap *regmap; 588c2ecf20Sopenharmony_ci struct iio_trigger *dready_trig; 598c2ecf20Sopenharmony_ci /* Ensure timestamp is naturally aligned */ 608c2ecf20Sopenharmony_ci struct { 618c2ecf20Sopenharmony_ci __be16 chans[3]; 628c2ecf20Sopenharmony_ci s64 timestamp __aligned(8); 638c2ecf20Sopenharmony_ci } scan; 648c2ecf20Sopenharmony_ci bool trigger_enabled; 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * MXC4005 can operate in the following ranges: 698c2ecf20Sopenharmony_ci * +/- 2G, 4G, 8G (the default +/-2G) 708c2ecf20Sopenharmony_ci * 718c2ecf20Sopenharmony_ci * (2 + 2) * 9.81 / (2^12 - 1) = 0.009582 728c2ecf20Sopenharmony_ci * (4 + 4) * 9.81 / (2^12 - 1) = 0.019164 738c2ecf20Sopenharmony_ci * (8 + 8) * 9.81 / (2^12 - 1) = 0.038329 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistatic const struct { 768c2ecf20Sopenharmony_ci u8 range; 778c2ecf20Sopenharmony_ci int scale; 788c2ecf20Sopenharmony_ci} mxc4005_scale_table[] = { 798c2ecf20Sopenharmony_ci {MXC4005_RANGE_2G, 9582}, 808c2ecf20Sopenharmony_ci {MXC4005_RANGE_4G, 19164}, 818c2ecf20Sopenharmony_ci {MXC4005_RANGE_8G, 38329}, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019164 0.038329"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic struct attribute *mxc4005_attributes[] = { 888c2ecf20Sopenharmony_ci &iio_const_attr_in_accel_scale_available.dev_attr.attr, 898c2ecf20Sopenharmony_ci NULL, 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic const struct attribute_group mxc4005_attrs_group = { 938c2ecf20Sopenharmony_ci .attrs = mxc4005_attributes, 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci switch (reg) { 998c2ecf20Sopenharmony_ci case MXC4005_REG_XOUT_UPPER: 1008c2ecf20Sopenharmony_ci case MXC4005_REG_XOUT_LOWER: 1018c2ecf20Sopenharmony_ci case MXC4005_REG_YOUT_UPPER: 1028c2ecf20Sopenharmony_ci case MXC4005_REG_YOUT_LOWER: 1038c2ecf20Sopenharmony_ci case MXC4005_REG_ZOUT_UPPER: 1048c2ecf20Sopenharmony_ci case MXC4005_REG_ZOUT_LOWER: 1058c2ecf20Sopenharmony_ci case MXC4005_REG_DEVICE_ID: 1068c2ecf20Sopenharmony_ci case MXC4005_REG_CONTROL: 1078c2ecf20Sopenharmony_ci return true; 1088c2ecf20Sopenharmony_ci default: 1098c2ecf20Sopenharmony_ci return false; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci switch (reg) { 1168c2ecf20Sopenharmony_ci case MXC4005_REG_INT_CLR1: 1178c2ecf20Sopenharmony_ci case MXC4005_REG_INT_MASK1: 1188c2ecf20Sopenharmony_ci case MXC4005_REG_CONTROL: 1198c2ecf20Sopenharmony_ci return true; 1208c2ecf20Sopenharmony_ci default: 1218c2ecf20Sopenharmony_ci return false; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic const struct regmap_config mxc4005_regmap_config = { 1268c2ecf20Sopenharmony_ci .name = MXC4005_REGMAP_NAME, 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci .reg_bits = 8, 1298c2ecf20Sopenharmony_ci .val_bits = 8, 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci .max_register = MXC4005_REG_DEVICE_ID, 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci .readable_reg = mxc4005_is_readable_reg, 1348c2ecf20Sopenharmony_ci .writeable_reg = mxc4005_is_writeable_reg, 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int mxc4005_read_xyz(struct mxc4005_data *data) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci int ret; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER, 1428c2ecf20Sopenharmony_ci data->scan.chans, sizeof(data->scan.chans)); 1438c2ecf20Sopenharmony_ci if (ret < 0) { 1448c2ecf20Sopenharmony_ci dev_err(data->dev, "failed to read axes\n"); 1458c2ecf20Sopenharmony_ci return ret; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int mxc4005_read_axis(struct mxc4005_data *data, 1528c2ecf20Sopenharmony_ci unsigned int addr) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci __be16 reg; 1558c2ecf20Sopenharmony_ci int ret; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ret = regmap_bulk_read(data->regmap, addr, ®, sizeof(reg)); 1588c2ecf20Sopenharmony_ci if (ret < 0) { 1598c2ecf20Sopenharmony_ci dev_err(data->dev, "failed to read reg %02x\n", addr); 1608c2ecf20Sopenharmony_ci return ret; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return be16_to_cpu(reg); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int mxc4005_read_scale(struct mxc4005_data *data) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci unsigned int reg; 1698c2ecf20Sopenharmony_ci int ret; 1708c2ecf20Sopenharmony_ci int i; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, ®); 1738c2ecf20Sopenharmony_ci if (ret < 0) { 1748c2ecf20Sopenharmony_ci dev_err(data->dev, "failed to read reg_control\n"); 1758c2ecf20Sopenharmony_ci return ret; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci i = reg >> MXC4005_CONTROL_FSR_SHIFT; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (i < 0 || i >= ARRAY_SIZE(mxc4005_scale_table)) 1818c2ecf20Sopenharmony_ci return -EINVAL; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return mxc4005_scale_table[i].scale; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int mxc4005_set_scale(struct mxc4005_data *data, int val) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci unsigned int reg; 1898c2ecf20Sopenharmony_ci int i; 1908c2ecf20Sopenharmony_ci int ret; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mxc4005_scale_table); i++) { 1938c2ecf20Sopenharmony_ci if (mxc4005_scale_table[i].scale == val) { 1948c2ecf20Sopenharmony_ci reg = i << MXC4005_CONTROL_FSR_SHIFT; 1958c2ecf20Sopenharmony_ci ret = regmap_update_bits(data->regmap, 1968c2ecf20Sopenharmony_ci MXC4005_REG_CONTROL, 1978c2ecf20Sopenharmony_ci MXC4005_REG_CONTROL_MASK_FSR, 1988c2ecf20Sopenharmony_ci reg); 1998c2ecf20Sopenharmony_ci if (ret < 0) 2008c2ecf20Sopenharmony_ci dev_err(data->dev, 2018c2ecf20Sopenharmony_ci "failed to write reg_control\n"); 2028c2ecf20Sopenharmony_ci return ret; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return -EINVAL; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int mxc4005_read_raw(struct iio_dev *indio_dev, 2108c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 2118c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct mxc4005_data *data = iio_priv(indio_dev); 2148c2ecf20Sopenharmony_ci int ret; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci switch (mask) { 2178c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 2188c2ecf20Sopenharmony_ci switch (chan->type) { 2198c2ecf20Sopenharmony_ci case IIO_ACCEL: 2208c2ecf20Sopenharmony_ci if (iio_buffer_enabled(indio_dev)) 2218c2ecf20Sopenharmony_ci return -EBUSY; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ret = mxc4005_read_axis(data, chan->address); 2248c2ecf20Sopenharmony_ci if (ret < 0) 2258c2ecf20Sopenharmony_ci return ret; 2268c2ecf20Sopenharmony_ci *val = sign_extend32(ret >> chan->scan_type.shift, 2278c2ecf20Sopenharmony_ci chan->scan_type.realbits - 1); 2288c2ecf20Sopenharmony_ci return IIO_VAL_INT; 2298c2ecf20Sopenharmony_ci default: 2308c2ecf20Sopenharmony_ci return -EINVAL; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 2338c2ecf20Sopenharmony_ci ret = mxc4005_read_scale(data); 2348c2ecf20Sopenharmony_ci if (ret < 0) 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci *val = 0; 2388c2ecf20Sopenharmony_ci *val2 = ret; 2398c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 2408c2ecf20Sopenharmony_ci default: 2418c2ecf20Sopenharmony_ci return -EINVAL; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int mxc4005_write_raw(struct iio_dev *indio_dev, 2468c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 2478c2ecf20Sopenharmony_ci int val, int val2, long mask) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct mxc4005_data *data = iio_priv(indio_dev); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci switch (mask) { 2528c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 2538c2ecf20Sopenharmony_ci if (val != 0) 2548c2ecf20Sopenharmony_ci return -EINVAL; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return mxc4005_set_scale(data, val2); 2578c2ecf20Sopenharmony_ci default: 2588c2ecf20Sopenharmony_ci return -EINVAL; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic const struct iio_info mxc4005_info = { 2638c2ecf20Sopenharmony_ci .read_raw = mxc4005_read_raw, 2648c2ecf20Sopenharmony_ci .write_raw = mxc4005_write_raw, 2658c2ecf20Sopenharmony_ci .attrs = &mxc4005_attrs_group, 2668c2ecf20Sopenharmony_ci}; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic const unsigned long mxc4005_scan_masks[] = { 2698c2ecf20Sopenharmony_ci BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), 2708c2ecf20Sopenharmony_ci 0 2718c2ecf20Sopenharmony_ci}; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci#define MXC4005_CHANNEL(_axis, _addr) { \ 2748c2ecf20Sopenharmony_ci .type = IIO_ACCEL, \ 2758c2ecf20Sopenharmony_ci .modified = 1, \ 2768c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_##_axis, \ 2778c2ecf20Sopenharmony_ci .address = _addr, \ 2788c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 2798c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 2808c2ecf20Sopenharmony_ci .scan_index = AXIS_##_axis, \ 2818c2ecf20Sopenharmony_ci .scan_type = { \ 2828c2ecf20Sopenharmony_ci .sign = 's', \ 2838c2ecf20Sopenharmony_ci .realbits = 12, \ 2848c2ecf20Sopenharmony_ci .storagebits = 16, \ 2858c2ecf20Sopenharmony_ci .shift = 4, \ 2868c2ecf20Sopenharmony_ci .endianness = IIO_BE, \ 2878c2ecf20Sopenharmony_ci }, \ 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic const struct iio_chan_spec mxc4005_channels[] = { 2918c2ecf20Sopenharmony_ci MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER), 2928c2ecf20Sopenharmony_ci MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER), 2938c2ecf20Sopenharmony_ci MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER), 2948c2ecf20Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(3), 2958c2ecf20Sopenharmony_ci}; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic irqreturn_t mxc4005_trigger_handler(int irq, void *private) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct iio_poll_func *pf = private; 3008c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = pf->indio_dev; 3018c2ecf20Sopenharmony_ci struct mxc4005_data *data = iio_priv(indio_dev); 3028c2ecf20Sopenharmony_ci int ret; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ret = mxc4005_read_xyz(data); 3058c2ecf20Sopenharmony_ci if (ret < 0) 3068c2ecf20Sopenharmony_ci goto err; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, 3098c2ecf20Sopenharmony_ci pf->timestamp); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cierr: 3128c2ecf20Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int mxc4005_clr_intr(struct mxc4005_data *data) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci int ret; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* clear interrupt */ 3228c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, 3238c2ecf20Sopenharmony_ci MXC4005_REG_INT_CLR1_BIT_DRDYC); 3248c2ecf20Sopenharmony_ci if (ret < 0) { 3258c2ecf20Sopenharmony_ci dev_err(data->dev, "failed to write to reg_int_clr1\n"); 3268c2ecf20Sopenharmony_ci return ret; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int mxc4005_set_trigger_state(struct iio_trigger *trig, 3338c2ecf20Sopenharmony_ci bool state) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 3368c2ecf20Sopenharmony_ci struct mxc4005_data *data = iio_priv(indio_dev); 3378c2ecf20Sopenharmony_ci int ret; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 3408c2ecf20Sopenharmony_ci if (state) { 3418c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, 3428c2ecf20Sopenharmony_ci MXC4005_REG_INT_MASK1_BIT_DRDYE); 3438c2ecf20Sopenharmony_ci } else { 3448c2ecf20Sopenharmony_ci ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, 3458c2ecf20Sopenharmony_ci ~MXC4005_REG_INT_MASK1_BIT_DRDYE); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (ret < 0) { 3498c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 3508c2ecf20Sopenharmony_ci dev_err(data->dev, "failed to update reg_int_mask1"); 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci data->trigger_enabled = state; 3558c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int mxc4005_trigger_try_reen(struct iio_trigger *trig) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 3638c2ecf20Sopenharmony_ci struct mxc4005_data *data = iio_priv(indio_dev); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (!data->dready_trig) 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return mxc4005_clr_intr(data); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic const struct iio_trigger_ops mxc4005_trigger_ops = { 3728c2ecf20Sopenharmony_ci .set_trigger_state = mxc4005_set_trigger_state, 3738c2ecf20Sopenharmony_ci .try_reenable = mxc4005_trigger_try_reen, 3748c2ecf20Sopenharmony_ci}; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int mxc4005_chip_init(struct mxc4005_data *data) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci int ret; 3798c2ecf20Sopenharmony_ci unsigned int reg; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ret = regmap_read(data->regmap, MXC4005_REG_DEVICE_ID, ®); 3828c2ecf20Sopenharmony_ci if (ret < 0) { 3838c2ecf20Sopenharmony_ci dev_err(data->dev, "failed to read chip id\n"); 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int mxc4005_probe(struct i2c_client *client, 3938c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct mxc4005_data *data; 3968c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 3978c2ecf20Sopenharmony_ci struct regmap *regmap; 3988c2ecf20Sopenharmony_ci int ret; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 4018c2ecf20Sopenharmony_ci if (!indio_dev) 4028c2ecf20Sopenharmony_ci return -ENOMEM; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci regmap = devm_regmap_init_i2c(client, &mxc4005_regmap_config); 4058c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 4068c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to initialize regmap\n"); 4078c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci data = iio_priv(indio_dev); 4118c2ecf20Sopenharmony_ci i2c_set_clientdata(client, indio_dev); 4128c2ecf20Sopenharmony_ci data->dev = &client->dev; 4138c2ecf20Sopenharmony_ci data->regmap = regmap; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci ret = mxc4005_chip_init(data); 4168c2ecf20Sopenharmony_ci if (ret < 0) { 4178c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to initialize chip\n"); 4188c2ecf20Sopenharmony_ci return ret; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci mutex_init(&data->mutex); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci indio_dev->channels = mxc4005_channels; 4248c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); 4258c2ecf20Sopenharmony_ci indio_dev->available_scan_masks = mxc4005_scan_masks; 4268c2ecf20Sopenharmony_ci indio_dev->name = MXC4005_DRV_NAME; 4278c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 4288c2ecf20Sopenharmony_ci indio_dev->info = &mxc4005_info; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, 4318c2ecf20Sopenharmony_ci iio_pollfunc_store_time, 4328c2ecf20Sopenharmony_ci mxc4005_trigger_handler, 4338c2ecf20Sopenharmony_ci NULL); 4348c2ecf20Sopenharmony_ci if (ret < 0) { 4358c2ecf20Sopenharmony_ci dev_err(&client->dev, 4368c2ecf20Sopenharmony_ci "failed to setup iio triggered buffer\n"); 4378c2ecf20Sopenharmony_ci return ret; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (client->irq > 0) { 4418c2ecf20Sopenharmony_ci data->dready_trig = devm_iio_trigger_alloc(&client->dev, 4428c2ecf20Sopenharmony_ci "%s-dev%d", 4438c2ecf20Sopenharmony_ci indio_dev->name, 4448c2ecf20Sopenharmony_ci indio_dev->id); 4458c2ecf20Sopenharmony_ci if (!data->dready_trig) 4468c2ecf20Sopenharmony_ci return -ENOMEM; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&client->dev, client->irq, 4498c2ecf20Sopenharmony_ci iio_trigger_generic_data_rdy_poll, 4508c2ecf20Sopenharmony_ci NULL, 4518c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | 4528c2ecf20Sopenharmony_ci IRQF_ONESHOT, 4538c2ecf20Sopenharmony_ci MXC4005_IRQ_NAME, 4548c2ecf20Sopenharmony_ci data->dready_trig); 4558c2ecf20Sopenharmony_ci if (ret) { 4568c2ecf20Sopenharmony_ci dev_err(&client->dev, 4578c2ecf20Sopenharmony_ci "failed to init threaded irq\n"); 4588c2ecf20Sopenharmony_ci return ret; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci data->dready_trig->dev.parent = &client->dev; 4628c2ecf20Sopenharmony_ci data->dready_trig->ops = &mxc4005_trigger_ops; 4638c2ecf20Sopenharmony_ci iio_trigger_set_drvdata(data->dready_trig, indio_dev); 4648c2ecf20Sopenharmony_ci ret = devm_iio_trigger_register(&client->dev, 4658c2ecf20Sopenharmony_ci data->dready_trig); 4668c2ecf20Sopenharmony_ci if (ret) { 4678c2ecf20Sopenharmony_ci dev_err(&client->dev, 4688c2ecf20Sopenharmony_ci "failed to register trigger\n"); 4698c2ecf20Sopenharmony_ci return ret; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci indio_dev->trig = iio_trigger_get(data->dready_trig); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return devm_iio_device_register(&client->dev, indio_dev); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic const struct acpi_device_id mxc4005_acpi_match[] = { 4798c2ecf20Sopenharmony_ci {"MXC4005", 0}, 4808c2ecf20Sopenharmony_ci {"MXC6655", 0}, 4818c2ecf20Sopenharmony_ci { }, 4828c2ecf20Sopenharmony_ci}; 4838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic const struct i2c_device_id mxc4005_id[] = { 4868c2ecf20Sopenharmony_ci {"mxc4005", 0}, 4878c2ecf20Sopenharmony_ci {"mxc6655", 0}, 4888c2ecf20Sopenharmony_ci { }, 4898c2ecf20Sopenharmony_ci}; 4908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mxc4005_id); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic struct i2c_driver mxc4005_driver = { 4938c2ecf20Sopenharmony_ci .driver = { 4948c2ecf20Sopenharmony_ci .name = MXC4005_DRV_NAME, 4958c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), 4968c2ecf20Sopenharmony_ci }, 4978c2ecf20Sopenharmony_ci .probe = mxc4005_probe, 4988c2ecf20Sopenharmony_ci .id_table = mxc4005_id, 4998c2ecf20Sopenharmony_ci}; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cimodule_i2c_driver(mxc4005_driver); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ciMODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>"); 5048c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 5058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MXC4005 3-axis accelerometer driver"); 506