1c7eeea93SPeter Meerwald /* 2c7eeea93SPeter Meerwald * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer 3c7eeea93SPeter Meerwald * 4c7eeea93SPeter Meerwald * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net> 5c7eeea93SPeter Meerwald * 6c7eeea93SPeter Meerwald * This file is subject to the terms and conditions of version 2 of 7c7eeea93SPeter Meerwald * the GNU General Public License. See the file COPYING in the main 8c7eeea93SPeter Meerwald * directory of this archive for more details. 9c7eeea93SPeter Meerwald * 10c7eeea93SPeter Meerwald * 7-bit I2C slave address 0x1c/0x1d (pin selectable) 11c7eeea93SPeter Meerwald * 1228e34278SMartin Fuzzey * TODO: orientation / freefall events, autosleep 13c7eeea93SPeter Meerwald */ 14c7eeea93SPeter Meerwald 15c7eeea93SPeter Meerwald #include <linux/module.h> 16c7eeea93SPeter Meerwald #include <linux/i2c.h> 17c7eeea93SPeter Meerwald #include <linux/iio/iio.h> 18c7eeea93SPeter Meerwald #include <linux/iio/sysfs.h> 19c7eeea93SPeter Meerwald #include <linux/iio/buffer.h> 20ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger.h> 21ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger_consumer.h> 22c7eeea93SPeter Meerwald #include <linux/iio/triggered_buffer.h> 2328e34278SMartin Fuzzey #include <linux/iio/events.h> 24c7eeea93SPeter Meerwald #include <linux/delay.h> 25c7eeea93SPeter Meerwald 26c7eeea93SPeter Meerwald #define MMA8452_STATUS 0x00 27*69abff81SHartmut Knaack #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) 28c7eeea93SPeter Meerwald #define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ 29c7eeea93SPeter Meerwald #define MMA8452_OUT_Y 0x03 30c7eeea93SPeter Meerwald #define MMA8452_OUT_Z 0x05 3128e34278SMartin Fuzzey #define MMA8452_INT_SRC 0x0c 32c7eeea93SPeter Meerwald #define MMA8452_WHO_AM_I 0x0d 33c7eeea93SPeter Meerwald #define MMA8452_DATA_CFG 0x0e 34*69abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0) 35*69abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_2G 0 36*69abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_4G 1 37*69abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_8G 2 38*69abff81SHartmut Knaack #define MMA8452_DATA_CFG_HPF_MASK BIT(4) 391e79841aSMartin Fuzzey #define MMA8452_HP_FILTER_CUTOFF 0x0f 40*69abff81SHartmut Knaack #define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0) 4128e34278SMartin Fuzzey #define MMA8452_TRANSIENT_CFG 0x1d 421e79841aSMartin Fuzzey #define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) 43*69abff81SHartmut Knaack #define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) 44*69abff81SHartmut Knaack #define MMA8452_TRANSIENT_CFG_ELE BIT(4) 4528e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC 0x1e 4628e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) 4728e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) 4828e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) 4928e34278SMartin Fuzzey #define MMA8452_TRANSIENT_THS 0x1f 50*69abff81SHartmut Knaack #define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0) 515dbbd19fSMartin Fuzzey #define MMA8452_TRANSIENT_COUNT 0x20 52c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG1 0x2a 53*69abff81SHartmut Knaack #define MMA8452_CTRL_ACTIVE BIT(0) 54*69abff81SHartmut Knaack #define MMA8452_CTRL_DR_MASK GENMASK(5, 3) 55*69abff81SHartmut Knaack #define MMA8452_CTRL_DR_SHIFT 3 56*69abff81SHartmut Knaack #define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ 57c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG2 0x2b 58ecabae71SMartin Fuzzey #define MMA8452_CTRL_REG2_RST BIT(6) 5928e34278SMartin Fuzzey #define MMA8452_CTRL_REG4 0x2d 6028e34278SMartin Fuzzey #define MMA8452_CTRL_REG5 0x2e 61*69abff81SHartmut Knaack #define MMA8452_OFF_X 0x2f 62*69abff81SHartmut Knaack #define MMA8452_OFF_Y 0x30 63*69abff81SHartmut Knaack #define MMA8452_OFF_Z 0x31 64c7eeea93SPeter Meerwald 652a17698cSMartin Fuzzey #define MMA8452_MAX_REG 0x31 662a17698cSMartin Fuzzey 67ae6d9ce0SMartin Fuzzey #define MMA8452_INT_DRDY BIT(0) 6828e34278SMartin Fuzzey #define MMA8452_INT_TRANS BIT(5) 6928e34278SMartin Fuzzey 70c7eeea93SPeter Meerwald #define MMA8452_DEVICE_ID 0x2a 71c7eeea93SPeter Meerwald 72c7eeea93SPeter Meerwald struct mma8452_data { 73c7eeea93SPeter Meerwald struct i2c_client *client; 74c7eeea93SPeter Meerwald struct mutex lock; 75c7eeea93SPeter Meerwald u8 ctrl_reg1; 76c7eeea93SPeter Meerwald u8 data_cfg; 77c7eeea93SPeter Meerwald }; 78c7eeea93SPeter Meerwald 79c7eeea93SPeter Meerwald static int mma8452_drdy(struct mma8452_data *data) 80c7eeea93SPeter Meerwald { 81c7eeea93SPeter Meerwald int tries = 150; 82c7eeea93SPeter Meerwald 83c7eeea93SPeter Meerwald while (tries-- > 0) { 84c7eeea93SPeter Meerwald int ret = i2c_smbus_read_byte_data(data->client, 85c7eeea93SPeter Meerwald MMA8452_STATUS); 86c7eeea93SPeter Meerwald if (ret < 0) 87c7eeea93SPeter Meerwald return ret; 88c7eeea93SPeter Meerwald if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) 89c7eeea93SPeter Meerwald return 0; 90c7eeea93SPeter Meerwald msleep(20); 91c7eeea93SPeter Meerwald } 92c7eeea93SPeter Meerwald 93c7eeea93SPeter Meerwald dev_err(&data->client->dev, "data not ready\n"); 94c7eeea93SPeter Meerwald return -EIO; 95c7eeea93SPeter Meerwald } 96c7eeea93SPeter Meerwald 97c7eeea93SPeter Meerwald static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) 98c7eeea93SPeter Meerwald { 99c7eeea93SPeter Meerwald int ret = mma8452_drdy(data); 100c7eeea93SPeter Meerwald if (ret < 0) 101c7eeea93SPeter Meerwald return ret; 102c7eeea93SPeter Meerwald return i2c_smbus_read_i2c_block_data(data->client, 103c7eeea93SPeter Meerwald MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf); 104c7eeea93SPeter Meerwald } 105c7eeea93SPeter Meerwald 106c7eeea93SPeter Meerwald static ssize_t mma8452_show_int_plus_micros(char *buf, 107c7eeea93SPeter Meerwald const int (*vals)[2], int n) 108c7eeea93SPeter Meerwald { 109c7eeea93SPeter Meerwald size_t len = 0; 110c7eeea93SPeter Meerwald 111c7eeea93SPeter Meerwald while (n-- > 0) 112c7eeea93SPeter Meerwald len += scnprintf(buf + len, PAGE_SIZE - len, 113c7eeea93SPeter Meerwald "%d.%06d ", vals[n][0], vals[n][1]); 114c7eeea93SPeter Meerwald 115c7eeea93SPeter Meerwald /* replace trailing space by newline */ 116c7eeea93SPeter Meerwald buf[len - 1] = '\n'; 117c7eeea93SPeter Meerwald 118c7eeea93SPeter Meerwald return len; 119c7eeea93SPeter Meerwald } 120c7eeea93SPeter Meerwald 121c7eeea93SPeter Meerwald static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n, 122c7eeea93SPeter Meerwald int val, int val2) 123c7eeea93SPeter Meerwald { 124c7eeea93SPeter Meerwald while (n-- > 0) 125c7eeea93SPeter Meerwald if (val == vals[n][0] && val2 == vals[n][1]) 126c7eeea93SPeter Meerwald return n; 127c7eeea93SPeter Meerwald 128c7eeea93SPeter Meerwald return -EINVAL; 129c7eeea93SPeter Meerwald } 130c7eeea93SPeter Meerwald 1315dbbd19fSMartin Fuzzey static int mma8452_get_odr_index(struct mma8452_data *data) 1325dbbd19fSMartin Fuzzey { 1335dbbd19fSMartin Fuzzey return (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >> 1345dbbd19fSMartin Fuzzey MMA8452_CTRL_DR_SHIFT; 1355dbbd19fSMartin Fuzzey } 1365dbbd19fSMartin Fuzzey 137c7eeea93SPeter Meerwald static const int mma8452_samp_freq[8][2] = { 138c7eeea93SPeter Meerwald {800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000}, 139c7eeea93SPeter Meerwald {6, 250000}, {1, 560000} 140c7eeea93SPeter Meerwald }; 141c7eeea93SPeter Meerwald 14271702e6eSMartin Fuzzey /* 14371702e6eSMartin Fuzzey * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048 14471702e6eSMartin Fuzzey * The userspace interface uses m/s^2 and we declare micro units 14571702e6eSMartin Fuzzey * So scale factor is given by: 14671702e6eSMartin Fuzzey * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 14771702e6eSMartin Fuzzey */ 148c7eeea93SPeter Meerwald static const int mma8452_scales[3][2] = { 14971702e6eSMartin Fuzzey {0, 9577}, {0, 19154}, {0, 38307} 150c7eeea93SPeter Meerwald }; 151c7eeea93SPeter Meerwald 1525dbbd19fSMartin Fuzzey /* Datasheet table 35 (step time vs sample frequency) */ 1535dbbd19fSMartin Fuzzey static const int mma8452_transient_time_step_us[8] = { 1545dbbd19fSMartin Fuzzey 1250, 1555dbbd19fSMartin Fuzzey 2500, 1565dbbd19fSMartin Fuzzey 5000, 1575dbbd19fSMartin Fuzzey 10000, 1585dbbd19fSMartin Fuzzey 20000, 1595dbbd19fSMartin Fuzzey 20000, 1605dbbd19fSMartin Fuzzey 20000, 1615dbbd19fSMartin Fuzzey 20000 1625dbbd19fSMartin Fuzzey }; 1635dbbd19fSMartin Fuzzey 1641e79841aSMartin Fuzzey /* Datasheet table 18 (normal mode) */ 1651e79841aSMartin Fuzzey static const int mma8452_hp_filter_cutoff[8][4][2] = { 1661e79841aSMartin Fuzzey { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 800 Hz sample */ 1671e79841aSMartin Fuzzey { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 400 Hz sample */ 1681e79841aSMartin Fuzzey { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, /* 200 Hz sample */ 1691e79841aSMartin Fuzzey { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, /* 100 Hz sample */ 1701e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 50 Hz sample */ 1711e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 12.5 Hz sample */ 1721e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 6.25 Hz sample */ 1731e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} } /* 1.56 Hz sample */ 1741e79841aSMartin Fuzzey }; 1751e79841aSMartin Fuzzey 176c7eeea93SPeter Meerwald static ssize_t mma8452_show_samp_freq_avail(struct device *dev, 177c7eeea93SPeter Meerwald struct device_attribute *attr, char *buf) 178c7eeea93SPeter Meerwald { 179c7eeea93SPeter Meerwald return mma8452_show_int_plus_micros(buf, mma8452_samp_freq, 180c7eeea93SPeter Meerwald ARRAY_SIZE(mma8452_samp_freq)); 181c7eeea93SPeter Meerwald } 182c7eeea93SPeter Meerwald 183c7eeea93SPeter Meerwald static ssize_t mma8452_show_scale_avail(struct device *dev, 184c7eeea93SPeter Meerwald struct device_attribute *attr, char *buf) 185c7eeea93SPeter Meerwald { 186c7eeea93SPeter Meerwald return mma8452_show_int_plus_micros(buf, mma8452_scales, 187c7eeea93SPeter Meerwald ARRAY_SIZE(mma8452_scales)); 188c7eeea93SPeter Meerwald } 189c7eeea93SPeter Meerwald 1901e79841aSMartin Fuzzey static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, 1911e79841aSMartin Fuzzey struct device_attribute *attr, 1921e79841aSMartin Fuzzey char *buf) 1931e79841aSMartin Fuzzey { 1941e79841aSMartin Fuzzey struct iio_dev *indio_dev = dev_to_iio_dev(dev); 1951e79841aSMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 1961e79841aSMartin Fuzzey int i = mma8452_get_odr_index(data); 1971e79841aSMartin Fuzzey 1981e79841aSMartin Fuzzey return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[i], 1991e79841aSMartin Fuzzey ARRAY_SIZE(mma8452_hp_filter_cutoff[0])); 2001e79841aSMartin Fuzzey } 2011e79841aSMartin Fuzzey 202c7eeea93SPeter Meerwald static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); 203c7eeea93SPeter Meerwald static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO, 204c7eeea93SPeter Meerwald mma8452_show_scale_avail, NULL, 0); 2051e79841aSMartin Fuzzey static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available, 2061e79841aSMartin Fuzzey S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); 207c7eeea93SPeter Meerwald 208c7eeea93SPeter Meerwald static int mma8452_get_samp_freq_index(struct mma8452_data *data, 209c7eeea93SPeter Meerwald int val, int val2) 210c7eeea93SPeter Meerwald { 211c7eeea93SPeter Meerwald return mma8452_get_int_plus_micros_index(mma8452_samp_freq, 212c7eeea93SPeter Meerwald ARRAY_SIZE(mma8452_samp_freq), val, val2); 213c7eeea93SPeter Meerwald } 214c7eeea93SPeter Meerwald 215c7eeea93SPeter Meerwald static int mma8452_get_scale_index(struct mma8452_data *data, 216c7eeea93SPeter Meerwald int val, int val2) 217c7eeea93SPeter Meerwald { 218c7eeea93SPeter Meerwald return mma8452_get_int_plus_micros_index(mma8452_scales, 219c7eeea93SPeter Meerwald ARRAY_SIZE(mma8452_scales), val, val2); 220c7eeea93SPeter Meerwald } 221c7eeea93SPeter Meerwald 2221e79841aSMartin Fuzzey static int mma8452_get_hp_filter_index(struct mma8452_data *data, 2231e79841aSMartin Fuzzey int val, int val2) 2241e79841aSMartin Fuzzey { 2251e79841aSMartin Fuzzey int i = mma8452_get_odr_index(data); 2261e79841aSMartin Fuzzey 2271e79841aSMartin Fuzzey return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i], 228001fceb9SHartmut Knaack ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2); 2291e79841aSMartin Fuzzey } 2301e79841aSMartin Fuzzey 2311e79841aSMartin Fuzzey static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz) 2321e79841aSMartin Fuzzey { 2331e79841aSMartin Fuzzey int i, ret; 2341e79841aSMartin Fuzzey 2351e79841aSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); 2361e79841aSMartin Fuzzey if (ret < 0) 2371e79841aSMartin Fuzzey return ret; 2381e79841aSMartin Fuzzey 2391e79841aSMartin Fuzzey i = mma8452_get_odr_index(data); 2401e79841aSMartin Fuzzey ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK; 2411e79841aSMartin Fuzzey *hz = mma8452_hp_filter_cutoff[i][ret][0]; 2421e79841aSMartin Fuzzey *uHz = mma8452_hp_filter_cutoff[i][ret][1]; 2431e79841aSMartin Fuzzey 2441e79841aSMartin Fuzzey return 0; 2451e79841aSMartin Fuzzey } 2461e79841aSMartin Fuzzey 247c7eeea93SPeter Meerwald static int mma8452_read_raw(struct iio_dev *indio_dev, 248c7eeea93SPeter Meerwald struct iio_chan_spec const *chan, 249c7eeea93SPeter Meerwald int *val, int *val2, long mask) 250c7eeea93SPeter Meerwald { 251c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 252c7eeea93SPeter Meerwald __be16 buffer[3]; 253c7eeea93SPeter Meerwald int i, ret; 254c7eeea93SPeter Meerwald 255c7eeea93SPeter Meerwald switch (mask) { 256c7eeea93SPeter Meerwald case IIO_CHAN_INFO_RAW: 257c7eeea93SPeter Meerwald if (iio_buffer_enabled(indio_dev)) 258c7eeea93SPeter Meerwald return -EBUSY; 259c7eeea93SPeter Meerwald 260c7eeea93SPeter Meerwald mutex_lock(&data->lock); 261c7eeea93SPeter Meerwald ret = mma8452_read(data, buffer); 262c7eeea93SPeter Meerwald mutex_unlock(&data->lock); 263c7eeea93SPeter Meerwald if (ret < 0) 264c7eeea93SPeter Meerwald return ret; 265c7eeea93SPeter Meerwald *val = sign_extend32( 266c7eeea93SPeter Meerwald be16_to_cpu(buffer[chan->scan_index]) >> 4, 11); 267c7eeea93SPeter Meerwald return IIO_VAL_INT; 268c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SCALE: 269c7eeea93SPeter Meerwald i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; 270c7eeea93SPeter Meerwald *val = mma8452_scales[i][0]; 271c7eeea93SPeter Meerwald *val2 = mma8452_scales[i][1]; 272c7eeea93SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 273c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SAMP_FREQ: 2745dbbd19fSMartin Fuzzey i = mma8452_get_odr_index(data); 275c7eeea93SPeter Meerwald *val = mma8452_samp_freq[i][0]; 276c7eeea93SPeter Meerwald *val2 = mma8452_samp_freq[i][1]; 277c7eeea93SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 278c7eeea93SPeter Meerwald case IIO_CHAN_INFO_CALIBBIAS: 279c7eeea93SPeter Meerwald ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X + 280c7eeea93SPeter Meerwald chan->scan_index); 281c7eeea93SPeter Meerwald if (ret < 0) 282c7eeea93SPeter Meerwald return ret; 283c7eeea93SPeter Meerwald *val = sign_extend32(ret, 7); 284c7eeea93SPeter Meerwald return IIO_VAL_INT; 2851e79841aSMartin Fuzzey case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 2861e79841aSMartin Fuzzey if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) { 2871e79841aSMartin Fuzzey ret = mma8452_read_hp_filter(data, val, val2); 2881e79841aSMartin Fuzzey if (ret < 0) 2891e79841aSMartin Fuzzey return ret; 2901e79841aSMartin Fuzzey } else { 2911e79841aSMartin Fuzzey *val = 0; 2921e79841aSMartin Fuzzey *val2 = 0; 2931e79841aSMartin Fuzzey } 2941e79841aSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 295c7eeea93SPeter Meerwald } 296c7eeea93SPeter Meerwald return -EINVAL; 297c7eeea93SPeter Meerwald } 298c7eeea93SPeter Meerwald 299c7eeea93SPeter Meerwald static int mma8452_standby(struct mma8452_data *data) 300c7eeea93SPeter Meerwald { 301c7eeea93SPeter Meerwald return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, 302c7eeea93SPeter Meerwald data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); 303c7eeea93SPeter Meerwald } 304c7eeea93SPeter Meerwald 305c7eeea93SPeter Meerwald static int mma8452_active(struct mma8452_data *data) 306c7eeea93SPeter Meerwald { 307c7eeea93SPeter Meerwald return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, 308c7eeea93SPeter Meerwald data->ctrl_reg1); 309c7eeea93SPeter Meerwald } 310c7eeea93SPeter Meerwald 311c7eeea93SPeter Meerwald static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) 312c7eeea93SPeter Meerwald { 313c7eeea93SPeter Meerwald int ret; 314c7eeea93SPeter Meerwald 315c7eeea93SPeter Meerwald mutex_lock(&data->lock); 316c7eeea93SPeter Meerwald 317c7eeea93SPeter Meerwald /* config can only be changed when in standby */ 318c7eeea93SPeter Meerwald ret = mma8452_standby(data); 319c7eeea93SPeter Meerwald if (ret < 0) 320c7eeea93SPeter Meerwald goto fail; 321c7eeea93SPeter Meerwald 322c7eeea93SPeter Meerwald ret = i2c_smbus_write_byte_data(data->client, reg, val); 323c7eeea93SPeter Meerwald if (ret < 0) 324c7eeea93SPeter Meerwald goto fail; 325c7eeea93SPeter Meerwald 326c7eeea93SPeter Meerwald ret = mma8452_active(data); 327c7eeea93SPeter Meerwald if (ret < 0) 328c7eeea93SPeter Meerwald goto fail; 329c7eeea93SPeter Meerwald 330c7eeea93SPeter Meerwald ret = 0; 331c7eeea93SPeter Meerwald fail: 332c7eeea93SPeter Meerwald mutex_unlock(&data->lock); 333c7eeea93SPeter Meerwald return ret; 334c7eeea93SPeter Meerwald } 335c7eeea93SPeter Meerwald 3361e79841aSMartin Fuzzey static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, 3371e79841aSMartin Fuzzey int val, int val2) 3381e79841aSMartin Fuzzey { 3391e79841aSMartin Fuzzey int i, reg; 3401e79841aSMartin Fuzzey 3411e79841aSMartin Fuzzey i = mma8452_get_hp_filter_index(data, val, val2); 3421e79841aSMartin Fuzzey if (i < 0) 343b9fddcdbSHartmut Knaack return i; 3441e79841aSMartin Fuzzey 3451e79841aSMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, 3461e79841aSMartin Fuzzey MMA8452_HP_FILTER_CUTOFF); 3471e79841aSMartin Fuzzey if (reg < 0) 3481e79841aSMartin Fuzzey return reg; 3491e79841aSMartin Fuzzey reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK; 3501e79841aSMartin Fuzzey reg |= i; 3511e79841aSMartin Fuzzey 3521e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg); 3531e79841aSMartin Fuzzey } 3541e79841aSMartin Fuzzey 355c7eeea93SPeter Meerwald static int mma8452_write_raw(struct iio_dev *indio_dev, 356c7eeea93SPeter Meerwald struct iio_chan_spec const *chan, 357c7eeea93SPeter Meerwald int val, int val2, long mask) 358c7eeea93SPeter Meerwald { 359c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 3601e79841aSMartin Fuzzey int i, ret; 361c7eeea93SPeter Meerwald 362c7eeea93SPeter Meerwald if (iio_buffer_enabled(indio_dev)) 363c7eeea93SPeter Meerwald return -EBUSY; 364c7eeea93SPeter Meerwald 365c7eeea93SPeter Meerwald switch (mask) { 366c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SAMP_FREQ: 367c7eeea93SPeter Meerwald i = mma8452_get_samp_freq_index(data, val, val2); 368c7eeea93SPeter Meerwald if (i < 0) 369b9fddcdbSHartmut Knaack return i; 370c7eeea93SPeter Meerwald 371c7eeea93SPeter Meerwald data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; 372c7eeea93SPeter Meerwald data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; 373c7eeea93SPeter Meerwald return mma8452_change_config(data, MMA8452_CTRL_REG1, 374c7eeea93SPeter Meerwald data->ctrl_reg1); 375c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SCALE: 376c7eeea93SPeter Meerwald i = mma8452_get_scale_index(data, val, val2); 377c7eeea93SPeter Meerwald if (i < 0) 378b9fddcdbSHartmut Knaack return i; 379c7eeea93SPeter Meerwald data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; 380c7eeea93SPeter Meerwald data->data_cfg |= i; 381c7eeea93SPeter Meerwald return mma8452_change_config(data, MMA8452_DATA_CFG, 382c7eeea93SPeter Meerwald data->data_cfg); 383c7eeea93SPeter Meerwald case IIO_CHAN_INFO_CALIBBIAS: 384c7eeea93SPeter Meerwald if (val < -128 || val > 127) 385c7eeea93SPeter Meerwald return -EINVAL; 386c7eeea93SPeter Meerwald return mma8452_change_config(data, MMA8452_OFF_X + 387c7eeea93SPeter Meerwald chan->scan_index, val); 3881e79841aSMartin Fuzzey 3891e79841aSMartin Fuzzey case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 3901e79841aSMartin Fuzzey if (val == 0 && val2 == 0) { 3911e79841aSMartin Fuzzey data->data_cfg &= ~MMA8452_DATA_CFG_HPF_MASK; 3921e79841aSMartin Fuzzey } else { 3931e79841aSMartin Fuzzey data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK; 3941e79841aSMartin Fuzzey ret = mma8452_set_hp_filter_frequency(data, val, val2); 3951e79841aSMartin Fuzzey if (ret < 0) 3961e79841aSMartin Fuzzey return ret; 3971e79841aSMartin Fuzzey } 3981e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_DATA_CFG, 3991e79841aSMartin Fuzzey data->data_cfg); 4001e79841aSMartin Fuzzey 401c7eeea93SPeter Meerwald default: 402c7eeea93SPeter Meerwald return -EINVAL; 403c7eeea93SPeter Meerwald } 404c7eeea93SPeter Meerwald } 405c7eeea93SPeter Meerwald 40628e34278SMartin Fuzzey static int mma8452_read_thresh(struct iio_dev *indio_dev, 40728e34278SMartin Fuzzey const struct iio_chan_spec *chan, 40828e34278SMartin Fuzzey enum iio_event_type type, 40928e34278SMartin Fuzzey enum iio_event_direction dir, 41028e34278SMartin Fuzzey enum iio_event_info info, 41128e34278SMartin Fuzzey int *val, int *val2) 41228e34278SMartin Fuzzey { 41328e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 4145dbbd19fSMartin Fuzzey int ret, us; 41528e34278SMartin Fuzzey 4165dbbd19fSMartin Fuzzey switch (info) { 4175dbbd19fSMartin Fuzzey case IIO_EV_INFO_VALUE: 4185dbbd19fSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, 4195dbbd19fSMartin Fuzzey MMA8452_TRANSIENT_THS); 42028e34278SMartin Fuzzey if (ret < 0) 42128e34278SMartin Fuzzey return ret; 42228e34278SMartin Fuzzey 42328e34278SMartin Fuzzey *val = ret & MMA8452_TRANSIENT_THS_MASK; 42428e34278SMartin Fuzzey return IIO_VAL_INT; 4255dbbd19fSMartin Fuzzey 4265dbbd19fSMartin Fuzzey case IIO_EV_INFO_PERIOD: 4275dbbd19fSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, 4285dbbd19fSMartin Fuzzey MMA8452_TRANSIENT_COUNT); 4295dbbd19fSMartin Fuzzey if (ret < 0) 4305dbbd19fSMartin Fuzzey return ret; 4315dbbd19fSMartin Fuzzey 4325dbbd19fSMartin Fuzzey us = ret * mma8452_transient_time_step_us[ 4335dbbd19fSMartin Fuzzey mma8452_get_odr_index(data)]; 4345dbbd19fSMartin Fuzzey *val = us / USEC_PER_SEC; 4355dbbd19fSMartin Fuzzey *val2 = us % USEC_PER_SEC; 4365dbbd19fSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 4375dbbd19fSMartin Fuzzey 4381e79841aSMartin Fuzzey case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: 4391e79841aSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, 4401e79841aSMartin Fuzzey MMA8452_TRANSIENT_CFG); 4411e79841aSMartin Fuzzey if (ret < 0) 4421e79841aSMartin Fuzzey return ret; 4431e79841aSMartin Fuzzey 4441e79841aSMartin Fuzzey if (ret & MMA8452_TRANSIENT_CFG_HPF_BYP) { 4451e79841aSMartin Fuzzey *val = 0; 4461e79841aSMartin Fuzzey *val2 = 0; 4471e79841aSMartin Fuzzey } else { 4481e79841aSMartin Fuzzey ret = mma8452_read_hp_filter(data, val, val2); 4491e79841aSMartin Fuzzey if (ret < 0) 4501e79841aSMartin Fuzzey return ret; 4511e79841aSMartin Fuzzey } 4521e79841aSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 4531e79841aSMartin Fuzzey 4545dbbd19fSMartin Fuzzey default: 4555dbbd19fSMartin Fuzzey return -EINVAL; 4565dbbd19fSMartin Fuzzey } 45728e34278SMartin Fuzzey } 45828e34278SMartin Fuzzey 45928e34278SMartin Fuzzey static int mma8452_write_thresh(struct iio_dev *indio_dev, 46028e34278SMartin Fuzzey const struct iio_chan_spec *chan, 46128e34278SMartin Fuzzey enum iio_event_type type, 46228e34278SMartin Fuzzey enum iio_event_direction dir, 46328e34278SMartin Fuzzey enum iio_event_info info, 46428e34278SMartin Fuzzey int val, int val2) 46528e34278SMartin Fuzzey { 46628e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 4671e79841aSMartin Fuzzey int ret, reg, steps; 46828e34278SMartin Fuzzey 4695dbbd19fSMartin Fuzzey switch (info) { 4705dbbd19fSMartin Fuzzey case IIO_EV_INFO_VALUE: 47111218226SHartmut Knaack if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK) 47211218226SHartmut Knaack return -EINVAL; 47311218226SHartmut Knaack 47411218226SHartmut Knaack return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val); 4755dbbd19fSMartin Fuzzey 4765dbbd19fSMartin Fuzzey case IIO_EV_INFO_PERIOD: 4775dbbd19fSMartin Fuzzey steps = (val * USEC_PER_SEC + val2) / 4785dbbd19fSMartin Fuzzey mma8452_transient_time_step_us[ 4795dbbd19fSMartin Fuzzey mma8452_get_odr_index(data)]; 4805dbbd19fSMartin Fuzzey 48111218226SHartmut Knaack if (steps < 0 || steps > 0xff) 4825dbbd19fSMartin Fuzzey return -EINVAL; 4835dbbd19fSMartin Fuzzey 4845dbbd19fSMartin Fuzzey return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT, 4855dbbd19fSMartin Fuzzey steps); 4861e79841aSMartin Fuzzey case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: 4871e79841aSMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, 4881e79841aSMartin Fuzzey MMA8452_TRANSIENT_CFG); 4891e79841aSMartin Fuzzey if (reg < 0) 4901e79841aSMartin Fuzzey return reg; 4911e79841aSMartin Fuzzey 4921e79841aSMartin Fuzzey if (val == 0 && val2 == 0) { 4931e79841aSMartin Fuzzey reg |= MMA8452_TRANSIENT_CFG_HPF_BYP; 4941e79841aSMartin Fuzzey } else { 4951e79841aSMartin Fuzzey reg &= ~MMA8452_TRANSIENT_CFG_HPF_BYP; 4961e79841aSMartin Fuzzey ret = mma8452_set_hp_filter_frequency(data, val, val2); 4971e79841aSMartin Fuzzey if (ret < 0) 4981e79841aSMartin Fuzzey return ret; 4991e79841aSMartin Fuzzey } 5001e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg); 5011e79841aSMartin Fuzzey 5025dbbd19fSMartin Fuzzey default: 5035dbbd19fSMartin Fuzzey return -EINVAL; 5045dbbd19fSMartin Fuzzey } 50528e34278SMartin Fuzzey } 50628e34278SMartin Fuzzey 50728e34278SMartin Fuzzey static int mma8452_read_event_config(struct iio_dev *indio_dev, 50828e34278SMartin Fuzzey const struct iio_chan_spec *chan, 50928e34278SMartin Fuzzey enum iio_event_type type, 51028e34278SMartin Fuzzey enum iio_event_direction dir) 51128e34278SMartin Fuzzey { 51228e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 51328e34278SMartin Fuzzey int ret; 51428e34278SMartin Fuzzey 51528e34278SMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); 51628e34278SMartin Fuzzey if (ret < 0) 51728e34278SMartin Fuzzey return ret; 51828e34278SMartin Fuzzey 51928e34278SMartin Fuzzey return ret & MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index) ? 1 : 0; 52028e34278SMartin Fuzzey } 52128e34278SMartin Fuzzey 52228e34278SMartin Fuzzey static int mma8452_write_event_config(struct iio_dev *indio_dev, 52328e34278SMartin Fuzzey const struct iio_chan_spec *chan, 52428e34278SMartin Fuzzey enum iio_event_type type, 52528e34278SMartin Fuzzey enum iio_event_direction dir, 52628e34278SMartin Fuzzey int state) 52728e34278SMartin Fuzzey { 52828e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 52928e34278SMartin Fuzzey int val; 53028e34278SMartin Fuzzey 53128e34278SMartin Fuzzey val = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); 53228e34278SMartin Fuzzey if (val < 0) 53328e34278SMartin Fuzzey return val; 53428e34278SMartin Fuzzey 53528e34278SMartin Fuzzey if (state) 53628e34278SMartin Fuzzey val |= MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index); 53728e34278SMartin Fuzzey else 53828e34278SMartin Fuzzey val &= ~MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index); 53928e34278SMartin Fuzzey 54028e34278SMartin Fuzzey val |= MMA8452_TRANSIENT_CFG_ELE; 54128e34278SMartin Fuzzey 54228e34278SMartin Fuzzey return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, val); 54328e34278SMartin Fuzzey } 54428e34278SMartin Fuzzey 54528e34278SMartin Fuzzey static void mma8452_transient_interrupt(struct iio_dev *indio_dev) 54628e34278SMartin Fuzzey { 54728e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 54828e34278SMartin Fuzzey s64 ts = iio_get_time_ns(); 54928e34278SMartin Fuzzey int src; 55028e34278SMartin Fuzzey 55128e34278SMartin Fuzzey src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC); 55228e34278SMartin Fuzzey if (src < 0) 55328e34278SMartin Fuzzey return; 55428e34278SMartin Fuzzey 55528e34278SMartin Fuzzey if (src & MMA8452_TRANSIENT_SRC_XTRANSE) 55628e34278SMartin Fuzzey iio_push_event(indio_dev, 55728e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, 55828e34278SMartin Fuzzey IIO_EV_TYPE_THRESH, 55928e34278SMartin Fuzzey IIO_EV_DIR_RISING), 56028e34278SMartin Fuzzey ts); 56128e34278SMartin Fuzzey 56228e34278SMartin Fuzzey if (src & MMA8452_TRANSIENT_SRC_YTRANSE) 56328e34278SMartin Fuzzey iio_push_event(indio_dev, 56428e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y, 56528e34278SMartin Fuzzey IIO_EV_TYPE_THRESH, 56628e34278SMartin Fuzzey IIO_EV_DIR_RISING), 56728e34278SMartin Fuzzey ts); 56828e34278SMartin Fuzzey 56928e34278SMartin Fuzzey if (src & MMA8452_TRANSIENT_SRC_ZTRANSE) 57028e34278SMartin Fuzzey iio_push_event(indio_dev, 57128e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z, 57228e34278SMartin Fuzzey IIO_EV_TYPE_THRESH, 57328e34278SMartin Fuzzey IIO_EV_DIR_RISING), 57428e34278SMartin Fuzzey ts); 57528e34278SMartin Fuzzey } 57628e34278SMartin Fuzzey 57728e34278SMartin Fuzzey static irqreturn_t mma8452_interrupt(int irq, void *p) 57828e34278SMartin Fuzzey { 57928e34278SMartin Fuzzey struct iio_dev *indio_dev = p; 58028e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 581ae6d9ce0SMartin Fuzzey int ret = IRQ_NONE; 58228e34278SMartin Fuzzey int src; 58328e34278SMartin Fuzzey 58428e34278SMartin Fuzzey src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC); 58528e34278SMartin Fuzzey if (src < 0) 58628e34278SMartin Fuzzey return IRQ_NONE; 58728e34278SMartin Fuzzey 588ae6d9ce0SMartin Fuzzey if (src & MMA8452_INT_DRDY) { 589ae6d9ce0SMartin Fuzzey iio_trigger_poll_chained(indio_dev->trig); 590ae6d9ce0SMartin Fuzzey ret = IRQ_HANDLED; 59128e34278SMartin Fuzzey } 59228e34278SMartin Fuzzey 593ae6d9ce0SMartin Fuzzey if (src & MMA8452_INT_TRANS) { 594ae6d9ce0SMartin Fuzzey mma8452_transient_interrupt(indio_dev); 595ae6d9ce0SMartin Fuzzey ret = IRQ_HANDLED; 596ae6d9ce0SMartin Fuzzey } 597ae6d9ce0SMartin Fuzzey 598ae6d9ce0SMartin Fuzzey return ret; 59928e34278SMartin Fuzzey } 60028e34278SMartin Fuzzey 601c7eeea93SPeter Meerwald static irqreturn_t mma8452_trigger_handler(int irq, void *p) 602c7eeea93SPeter Meerwald { 603c7eeea93SPeter Meerwald struct iio_poll_func *pf = p; 604c7eeea93SPeter Meerwald struct iio_dev *indio_dev = pf->indio_dev; 605c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 606c7eeea93SPeter Meerwald u8 buffer[16]; /* 3 16-bit channels + padding + ts */ 607c7eeea93SPeter Meerwald int ret; 608c7eeea93SPeter Meerwald 609c7eeea93SPeter Meerwald ret = mma8452_read(data, (__be16 *) buffer); 610c7eeea93SPeter Meerwald if (ret < 0) 611c7eeea93SPeter Meerwald goto done; 612c7eeea93SPeter Meerwald 613c7eeea93SPeter Meerwald iio_push_to_buffers_with_timestamp(indio_dev, buffer, 614c7eeea93SPeter Meerwald iio_get_time_ns()); 615c7eeea93SPeter Meerwald 616c7eeea93SPeter Meerwald done: 617c7eeea93SPeter Meerwald iio_trigger_notify_done(indio_dev->trig); 618c7eeea93SPeter Meerwald return IRQ_HANDLED; 619c7eeea93SPeter Meerwald } 620c7eeea93SPeter Meerwald 6212a17698cSMartin Fuzzey static int mma8452_reg_access_dbg(struct iio_dev *indio_dev, 6222a17698cSMartin Fuzzey unsigned reg, unsigned writeval, 6232a17698cSMartin Fuzzey unsigned *readval) 6242a17698cSMartin Fuzzey { 6252a17698cSMartin Fuzzey int ret; 6262a17698cSMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 6272a17698cSMartin Fuzzey 6282a17698cSMartin Fuzzey if (reg > MMA8452_MAX_REG) 6292a17698cSMartin Fuzzey return -EINVAL; 6302a17698cSMartin Fuzzey 6312a17698cSMartin Fuzzey if (!readval) 6322a17698cSMartin Fuzzey return mma8452_change_config(data, reg, writeval); 6332a17698cSMartin Fuzzey 6342a17698cSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, reg); 6352a17698cSMartin Fuzzey if (ret < 0) 6362a17698cSMartin Fuzzey return ret; 6372a17698cSMartin Fuzzey 6382a17698cSMartin Fuzzey *readval = ret; 6392a17698cSMartin Fuzzey 6402a17698cSMartin Fuzzey return 0; 6412a17698cSMartin Fuzzey } 6422a17698cSMartin Fuzzey 64328e34278SMartin Fuzzey static const struct iio_event_spec mma8452_transient_event[] = { 64428e34278SMartin Fuzzey { 64528e34278SMartin Fuzzey .type = IIO_EV_TYPE_THRESH, 64628e34278SMartin Fuzzey .dir = IIO_EV_DIR_RISING, 64728e34278SMartin Fuzzey .mask_separate = BIT(IIO_EV_INFO_ENABLE), 6485dbbd19fSMartin Fuzzey .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 6491e79841aSMartin Fuzzey BIT(IIO_EV_INFO_PERIOD) | 6501e79841aSMartin Fuzzey BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB) 65128e34278SMartin Fuzzey }, 65228e34278SMartin Fuzzey }; 65328e34278SMartin Fuzzey 65428e34278SMartin Fuzzey /* 65528e34278SMartin Fuzzey * Threshold is configured in fixed 8G/127 steps regardless of 65628e34278SMartin Fuzzey * currently selected scale for measurement. 65728e34278SMartin Fuzzey */ 65828e34278SMartin Fuzzey static IIO_CONST_ATTR_NAMED(accel_transient_scale, in_accel_scale, "0.617742"); 65928e34278SMartin Fuzzey 66028e34278SMartin Fuzzey static struct attribute *mma8452_event_attributes[] = { 66128e34278SMartin Fuzzey &iio_const_attr_accel_transient_scale.dev_attr.attr, 66228e34278SMartin Fuzzey NULL, 66328e34278SMartin Fuzzey }; 66428e34278SMartin Fuzzey 66528e34278SMartin Fuzzey static struct attribute_group mma8452_event_attribute_group = { 66628e34278SMartin Fuzzey .attrs = mma8452_event_attributes, 66728e34278SMartin Fuzzey .name = "events", 66828e34278SMartin Fuzzey }; 66928e34278SMartin Fuzzey 670c7eeea93SPeter Meerwald #define MMA8452_CHANNEL(axis, idx) { \ 671c7eeea93SPeter Meerwald .type = IIO_ACCEL, \ 672c7eeea93SPeter Meerwald .modified = 1, \ 673c7eeea93SPeter Meerwald .channel2 = IIO_MOD_##axis, \ 674c7eeea93SPeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 675c7eeea93SPeter Meerwald BIT(IIO_CHAN_INFO_CALIBBIAS), \ 676c7eeea93SPeter Meerwald .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 6771e79841aSMartin Fuzzey BIT(IIO_CHAN_INFO_SCALE) | \ 6781e79841aSMartin Fuzzey BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ 679c7eeea93SPeter Meerwald .scan_index = idx, \ 680c7eeea93SPeter Meerwald .scan_type = { \ 681c7eeea93SPeter Meerwald .sign = 's', \ 682c7eeea93SPeter Meerwald .realbits = 12, \ 683c7eeea93SPeter Meerwald .storagebits = 16, \ 684c7eeea93SPeter Meerwald .shift = 4, \ 685c7eeea93SPeter Meerwald .endianness = IIO_BE, \ 686c7eeea93SPeter Meerwald }, \ 68728e34278SMartin Fuzzey .event_spec = mma8452_transient_event, \ 68828e34278SMartin Fuzzey .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \ 689c7eeea93SPeter Meerwald } 690c7eeea93SPeter Meerwald 691c7eeea93SPeter Meerwald static const struct iio_chan_spec mma8452_channels[] = { 692c7eeea93SPeter Meerwald MMA8452_CHANNEL(X, 0), 693c7eeea93SPeter Meerwald MMA8452_CHANNEL(Y, 1), 694c7eeea93SPeter Meerwald MMA8452_CHANNEL(Z, 2), 695c7eeea93SPeter Meerwald IIO_CHAN_SOFT_TIMESTAMP(3), 696c7eeea93SPeter Meerwald }; 697c7eeea93SPeter Meerwald 698c7eeea93SPeter Meerwald static struct attribute *mma8452_attributes[] = { 699c7eeea93SPeter Meerwald &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 700c7eeea93SPeter Meerwald &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 7011e79841aSMartin Fuzzey &iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr, 702c7eeea93SPeter Meerwald NULL 703c7eeea93SPeter Meerwald }; 704c7eeea93SPeter Meerwald 705c7eeea93SPeter Meerwald static const struct attribute_group mma8452_group = { 706c7eeea93SPeter Meerwald .attrs = mma8452_attributes, 707c7eeea93SPeter Meerwald }; 708c7eeea93SPeter Meerwald 709c7eeea93SPeter Meerwald static const struct iio_info mma8452_info = { 710c7eeea93SPeter Meerwald .attrs = &mma8452_group, 711c7eeea93SPeter Meerwald .read_raw = &mma8452_read_raw, 712c7eeea93SPeter Meerwald .write_raw = &mma8452_write_raw, 71328e34278SMartin Fuzzey .event_attrs = &mma8452_event_attribute_group, 71428e34278SMartin Fuzzey .read_event_value = &mma8452_read_thresh, 71528e34278SMartin Fuzzey .write_event_value = &mma8452_write_thresh, 71628e34278SMartin Fuzzey .read_event_config = &mma8452_read_event_config, 71728e34278SMartin Fuzzey .write_event_config = &mma8452_write_event_config, 7182a17698cSMartin Fuzzey .debugfs_reg_access = &mma8452_reg_access_dbg, 719c7eeea93SPeter Meerwald .driver_module = THIS_MODULE, 720c7eeea93SPeter Meerwald }; 721c7eeea93SPeter Meerwald 722c7eeea93SPeter Meerwald static const unsigned long mma8452_scan_masks[] = {0x7, 0}; 723c7eeea93SPeter Meerwald 724ae6d9ce0SMartin Fuzzey static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig, 725ae6d9ce0SMartin Fuzzey bool state) 726ae6d9ce0SMartin Fuzzey { 727ae6d9ce0SMartin Fuzzey struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 728ae6d9ce0SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 729ae6d9ce0SMartin Fuzzey int reg; 730ae6d9ce0SMartin Fuzzey 731ae6d9ce0SMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4); 732ae6d9ce0SMartin Fuzzey if (reg < 0) 733ae6d9ce0SMartin Fuzzey return reg; 734ae6d9ce0SMartin Fuzzey 735ae6d9ce0SMartin Fuzzey if (state) 736ae6d9ce0SMartin Fuzzey reg |= MMA8452_INT_DRDY; 737ae6d9ce0SMartin Fuzzey else 738ae6d9ce0SMartin Fuzzey reg &= ~MMA8452_INT_DRDY; 739ae6d9ce0SMartin Fuzzey 740ae6d9ce0SMartin Fuzzey return mma8452_change_config(data, MMA8452_CTRL_REG4, reg); 741ae6d9ce0SMartin Fuzzey } 742ae6d9ce0SMartin Fuzzey 743ae6d9ce0SMartin Fuzzey static int mma8452_validate_device(struct iio_trigger *trig, 744ae6d9ce0SMartin Fuzzey struct iio_dev *indio_dev) 745ae6d9ce0SMartin Fuzzey { 746ae6d9ce0SMartin Fuzzey struct iio_dev *indio = iio_trigger_get_drvdata(trig); 747ae6d9ce0SMartin Fuzzey 748ae6d9ce0SMartin Fuzzey if (indio != indio_dev) 749ae6d9ce0SMartin Fuzzey return -EINVAL; 750ae6d9ce0SMartin Fuzzey 751ae6d9ce0SMartin Fuzzey return 0; 752ae6d9ce0SMartin Fuzzey } 753ae6d9ce0SMartin Fuzzey 754ae6d9ce0SMartin Fuzzey static const struct iio_trigger_ops mma8452_trigger_ops = { 755ae6d9ce0SMartin Fuzzey .set_trigger_state = mma8452_data_rdy_trigger_set_state, 756ae6d9ce0SMartin Fuzzey .validate_device = mma8452_validate_device, 757ae6d9ce0SMartin Fuzzey .owner = THIS_MODULE, 758ae6d9ce0SMartin Fuzzey }; 759ae6d9ce0SMartin Fuzzey 760ae6d9ce0SMartin Fuzzey static int mma8452_trigger_setup(struct iio_dev *indio_dev) 761ae6d9ce0SMartin Fuzzey { 762ae6d9ce0SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 763ae6d9ce0SMartin Fuzzey struct iio_trigger *trig; 764ae6d9ce0SMartin Fuzzey int ret; 765ae6d9ce0SMartin Fuzzey 766ae6d9ce0SMartin Fuzzey trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d", 767ae6d9ce0SMartin Fuzzey indio_dev->name, 768ae6d9ce0SMartin Fuzzey indio_dev->id); 769ae6d9ce0SMartin Fuzzey if (!trig) 770ae6d9ce0SMartin Fuzzey return -ENOMEM; 771ae6d9ce0SMartin Fuzzey 772ae6d9ce0SMartin Fuzzey trig->dev.parent = &data->client->dev; 773ae6d9ce0SMartin Fuzzey trig->ops = &mma8452_trigger_ops; 774ae6d9ce0SMartin Fuzzey iio_trigger_set_drvdata(trig, indio_dev); 775ae6d9ce0SMartin Fuzzey 776ae6d9ce0SMartin Fuzzey ret = iio_trigger_register(trig); 777ae6d9ce0SMartin Fuzzey if (ret) 778ae6d9ce0SMartin Fuzzey return ret; 779ae6d9ce0SMartin Fuzzey 780ae6d9ce0SMartin Fuzzey indio_dev->trig = trig; 781ae6d9ce0SMartin Fuzzey return 0; 782ae6d9ce0SMartin Fuzzey } 783ae6d9ce0SMartin Fuzzey 784ae6d9ce0SMartin Fuzzey static void mma8452_trigger_cleanup(struct iio_dev *indio_dev) 785ae6d9ce0SMartin Fuzzey { 786ae6d9ce0SMartin Fuzzey if (indio_dev->trig) 787ae6d9ce0SMartin Fuzzey iio_trigger_unregister(indio_dev->trig); 788ae6d9ce0SMartin Fuzzey } 789ae6d9ce0SMartin Fuzzey 790ecabae71SMartin Fuzzey static int mma8452_reset(struct i2c_client *client) 791ecabae71SMartin Fuzzey { 792ecabae71SMartin Fuzzey int i; 793ecabae71SMartin Fuzzey int ret; 794ecabae71SMartin Fuzzey 795ecabae71SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2, 796ecabae71SMartin Fuzzey MMA8452_CTRL_REG2_RST); 797ecabae71SMartin Fuzzey if (ret < 0) 798ecabae71SMartin Fuzzey return ret; 799ecabae71SMartin Fuzzey 800ecabae71SMartin Fuzzey for (i = 0; i < 10; i++) { 801ecabae71SMartin Fuzzey usleep_range(100, 200); 802ecabae71SMartin Fuzzey ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2); 803ecabae71SMartin Fuzzey if (ret == -EIO) 804ecabae71SMartin Fuzzey continue; /* I2C comm reset */ 805ecabae71SMartin Fuzzey if (ret < 0) 806ecabae71SMartin Fuzzey return ret; 807ecabae71SMartin Fuzzey if (!(ret & MMA8452_CTRL_REG2_RST)) 808ecabae71SMartin Fuzzey return 0; 809ecabae71SMartin Fuzzey } 810ecabae71SMartin Fuzzey 811ecabae71SMartin Fuzzey return -ETIMEDOUT; 812ecabae71SMartin Fuzzey } 813ecabae71SMartin Fuzzey 814c7eeea93SPeter Meerwald static int mma8452_probe(struct i2c_client *client, 815c7eeea93SPeter Meerwald const struct i2c_device_id *id) 816c7eeea93SPeter Meerwald { 817c7eeea93SPeter Meerwald struct mma8452_data *data; 818c7eeea93SPeter Meerwald struct iio_dev *indio_dev; 819c7eeea93SPeter Meerwald int ret; 820c7eeea93SPeter Meerwald 821c7eeea93SPeter Meerwald ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); 822c7eeea93SPeter Meerwald if (ret < 0) 823c7eeea93SPeter Meerwald return ret; 824c7eeea93SPeter Meerwald if (ret != MMA8452_DEVICE_ID) 825c7eeea93SPeter Meerwald return -ENODEV; 826c7eeea93SPeter Meerwald 827c7eeea93SPeter Meerwald indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 828c7eeea93SPeter Meerwald if (!indio_dev) 829c7eeea93SPeter Meerwald return -ENOMEM; 830c7eeea93SPeter Meerwald 831c7eeea93SPeter Meerwald data = iio_priv(indio_dev); 832c7eeea93SPeter Meerwald data->client = client; 833c7eeea93SPeter Meerwald mutex_init(&data->lock); 834c7eeea93SPeter Meerwald 835c7eeea93SPeter Meerwald i2c_set_clientdata(client, indio_dev); 836c7eeea93SPeter Meerwald indio_dev->info = &mma8452_info; 837c7eeea93SPeter Meerwald indio_dev->name = id->name; 838c7eeea93SPeter Meerwald indio_dev->dev.parent = &client->dev; 839c7eeea93SPeter Meerwald indio_dev->modes = INDIO_DIRECT_MODE; 840c7eeea93SPeter Meerwald indio_dev->channels = mma8452_channels; 841c7eeea93SPeter Meerwald indio_dev->num_channels = ARRAY_SIZE(mma8452_channels); 842c7eeea93SPeter Meerwald indio_dev->available_scan_masks = mma8452_scan_masks; 843c7eeea93SPeter Meerwald 844ecabae71SMartin Fuzzey ret = mma8452_reset(client); 845c7eeea93SPeter Meerwald if (ret < 0) 846c7eeea93SPeter Meerwald return ret; 847c7eeea93SPeter Meerwald 848c7eeea93SPeter Meerwald data->data_cfg = MMA8452_DATA_CFG_FS_2G; 849c7eeea93SPeter Meerwald ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, 850c7eeea93SPeter Meerwald data->data_cfg); 851c7eeea93SPeter Meerwald if (ret < 0) 852c7eeea93SPeter Meerwald return ret; 853c7eeea93SPeter Meerwald 85428e34278SMartin Fuzzey /* 85528e34278SMartin Fuzzey * By default set transient threshold to max to avoid events if 85628e34278SMartin Fuzzey * enabling without configuring threshold. 85728e34278SMartin Fuzzey */ 85828e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS, 85928e34278SMartin Fuzzey MMA8452_TRANSIENT_THS_MASK); 86028e34278SMartin Fuzzey if (ret < 0) 86128e34278SMartin Fuzzey return ret; 86228e34278SMartin Fuzzey 86328e34278SMartin Fuzzey if (client->irq) { 86428e34278SMartin Fuzzey /* 86528e34278SMartin Fuzzey * Although we enable the transient interrupt source once and 86628e34278SMartin Fuzzey * for all here the transient event detection itself is not 86728e34278SMartin Fuzzey * enabled until userspace asks for it by 86828e34278SMartin Fuzzey * mma8452_write_event_config() 86928e34278SMartin Fuzzey */ 870ae6d9ce0SMartin Fuzzey int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS; 871ae6d9ce0SMartin Fuzzey int enabled_interrupts = MMA8452_INT_TRANS; 87228e34278SMartin Fuzzey 87328e34278SMartin Fuzzey /* Assume wired to INT1 pin */ 87428e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, 87528e34278SMartin Fuzzey MMA8452_CTRL_REG5, 87628e34278SMartin Fuzzey supported_interrupts); 87728e34278SMartin Fuzzey if (ret < 0) 87828e34278SMartin Fuzzey return ret; 87928e34278SMartin Fuzzey 88028e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, 88128e34278SMartin Fuzzey MMA8452_CTRL_REG4, 882ae6d9ce0SMartin Fuzzey enabled_interrupts); 883ae6d9ce0SMartin Fuzzey if (ret < 0) 884ae6d9ce0SMartin Fuzzey return ret; 885ae6d9ce0SMartin Fuzzey 886ae6d9ce0SMartin Fuzzey ret = mma8452_trigger_setup(indio_dev); 88728e34278SMartin Fuzzey if (ret < 0) 88828e34278SMartin Fuzzey return ret; 88928e34278SMartin Fuzzey } 89028e34278SMartin Fuzzey 891ecabae71SMartin Fuzzey data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | 892ecabae71SMartin Fuzzey (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); 893ecabae71SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1, 894ecabae71SMartin Fuzzey data->ctrl_reg1); 895ecabae71SMartin Fuzzey if (ret < 0) 896ae6d9ce0SMartin Fuzzey goto trigger_cleanup; 897ecabae71SMartin Fuzzey 898c7eeea93SPeter Meerwald ret = iio_triggered_buffer_setup(indio_dev, NULL, 899c7eeea93SPeter Meerwald mma8452_trigger_handler, NULL); 900c7eeea93SPeter Meerwald if (ret < 0) 901ae6d9ce0SMartin Fuzzey goto trigger_cleanup; 902c7eeea93SPeter Meerwald 90328e34278SMartin Fuzzey if (client->irq) { 90428e34278SMartin Fuzzey ret = devm_request_threaded_irq(&client->dev, 90528e34278SMartin Fuzzey client->irq, 90628e34278SMartin Fuzzey NULL, mma8452_interrupt, 90728e34278SMartin Fuzzey IRQF_TRIGGER_LOW | IRQF_ONESHOT, 90828e34278SMartin Fuzzey client->name, indio_dev); 90928e34278SMartin Fuzzey if (ret) 91028e34278SMartin Fuzzey goto buffer_cleanup; 91128e34278SMartin Fuzzey } 91228e34278SMartin Fuzzey 913c7eeea93SPeter Meerwald ret = iio_device_register(indio_dev); 914c7eeea93SPeter Meerwald if (ret < 0) 915c7eeea93SPeter Meerwald goto buffer_cleanup; 91628e34278SMartin Fuzzey 917c7eeea93SPeter Meerwald return 0; 918c7eeea93SPeter Meerwald 919c7eeea93SPeter Meerwald buffer_cleanup: 920c7eeea93SPeter Meerwald iio_triggered_buffer_cleanup(indio_dev); 921ae6d9ce0SMartin Fuzzey 922ae6d9ce0SMartin Fuzzey trigger_cleanup: 923ae6d9ce0SMartin Fuzzey mma8452_trigger_cleanup(indio_dev); 924ae6d9ce0SMartin Fuzzey 925c7eeea93SPeter Meerwald return ret; 926c7eeea93SPeter Meerwald } 927c7eeea93SPeter Meerwald 928c7eeea93SPeter Meerwald static int mma8452_remove(struct i2c_client *client) 929c7eeea93SPeter Meerwald { 930c7eeea93SPeter Meerwald struct iio_dev *indio_dev = i2c_get_clientdata(client); 931c7eeea93SPeter Meerwald 932c7eeea93SPeter Meerwald iio_device_unregister(indio_dev); 933c7eeea93SPeter Meerwald iio_triggered_buffer_cleanup(indio_dev); 934ae6d9ce0SMartin Fuzzey mma8452_trigger_cleanup(indio_dev); 935c7eeea93SPeter Meerwald mma8452_standby(iio_priv(indio_dev)); 936c7eeea93SPeter Meerwald 937c7eeea93SPeter Meerwald return 0; 938c7eeea93SPeter Meerwald } 939c7eeea93SPeter Meerwald 940c7eeea93SPeter Meerwald #ifdef CONFIG_PM_SLEEP 941c7eeea93SPeter Meerwald static int mma8452_suspend(struct device *dev) 942c7eeea93SPeter Meerwald { 943c7eeea93SPeter Meerwald return mma8452_standby(iio_priv(i2c_get_clientdata( 944c7eeea93SPeter Meerwald to_i2c_client(dev)))); 945c7eeea93SPeter Meerwald } 946c7eeea93SPeter Meerwald 947c7eeea93SPeter Meerwald static int mma8452_resume(struct device *dev) 948c7eeea93SPeter Meerwald { 949c7eeea93SPeter Meerwald return mma8452_active(iio_priv(i2c_get_clientdata( 950c7eeea93SPeter Meerwald to_i2c_client(dev)))); 951c7eeea93SPeter Meerwald } 952c7eeea93SPeter Meerwald 953c7eeea93SPeter Meerwald static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume); 954c7eeea93SPeter Meerwald #define MMA8452_PM_OPS (&mma8452_pm_ops) 955c7eeea93SPeter Meerwald #else 956c7eeea93SPeter Meerwald #define MMA8452_PM_OPS NULL 957c7eeea93SPeter Meerwald #endif 958c7eeea93SPeter Meerwald 959c7eeea93SPeter Meerwald static const struct i2c_device_id mma8452_id[] = { 960c7eeea93SPeter Meerwald { "mma8452", 0 }, 961c7eeea93SPeter Meerwald { } 962c7eeea93SPeter Meerwald }; 963c7eeea93SPeter Meerwald MODULE_DEVICE_TABLE(i2c, mma8452_id); 964c7eeea93SPeter Meerwald 965a3fb96a8SMartin Fuzzey static const struct of_device_id mma8452_dt_ids[] = { 966a3fb96a8SMartin Fuzzey { .compatible = "fsl,mma8452" }, 967a3fb96a8SMartin Fuzzey { } 968a3fb96a8SMartin Fuzzey }; 969119c4fceSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, mma8452_dt_ids); 970a3fb96a8SMartin Fuzzey 971c7eeea93SPeter Meerwald static struct i2c_driver mma8452_driver = { 972c7eeea93SPeter Meerwald .driver = { 973c7eeea93SPeter Meerwald .name = "mma8452", 974a3fb96a8SMartin Fuzzey .of_match_table = of_match_ptr(mma8452_dt_ids), 975c7eeea93SPeter Meerwald .pm = MMA8452_PM_OPS, 976c7eeea93SPeter Meerwald }, 977c7eeea93SPeter Meerwald .probe = mma8452_probe, 978c7eeea93SPeter Meerwald .remove = mma8452_remove, 979c7eeea93SPeter Meerwald .id_table = mma8452_id, 980c7eeea93SPeter Meerwald }; 981c7eeea93SPeter Meerwald module_i2c_driver(mma8452_driver); 982c7eeea93SPeter Meerwald 983c7eeea93SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 984c7eeea93SPeter Meerwald MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver"); 985c7eeea93SPeter Meerwald MODULE_LICENSE("GPL"); 986