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> 25*c3cdd6e4SMartin Kepplinger #include <linux/of_device.h> 26c7eeea93SPeter Meerwald 27c7eeea93SPeter Meerwald #define MMA8452_STATUS 0x00 2869abff81SHartmut Knaack #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) 29c7eeea93SPeter Meerwald #define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ 30c7eeea93SPeter Meerwald #define MMA8452_OUT_Y 0x03 31c7eeea93SPeter Meerwald #define MMA8452_OUT_Z 0x05 3228e34278SMartin Fuzzey #define MMA8452_INT_SRC 0x0c 33c7eeea93SPeter Meerwald #define MMA8452_WHO_AM_I 0x0d 34c7eeea93SPeter Meerwald #define MMA8452_DATA_CFG 0x0e 3569abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0) 3669abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_2G 0 3769abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_4G 1 3869abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_8G 2 3969abff81SHartmut Knaack #define MMA8452_DATA_CFG_HPF_MASK BIT(4) 401e79841aSMartin Fuzzey #define MMA8452_HP_FILTER_CUTOFF 0x0f 4169abff81SHartmut Knaack #define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0) 4228e34278SMartin Fuzzey #define MMA8452_TRANSIENT_CFG 0x1d 431e79841aSMartin Fuzzey #define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) 4469abff81SHartmut Knaack #define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) 4569abff81SHartmut Knaack #define MMA8452_TRANSIENT_CFG_ELE BIT(4) 4628e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC 0x1e 4728e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) 4828e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) 4928e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) 5028e34278SMartin Fuzzey #define MMA8452_TRANSIENT_THS 0x1f 5169abff81SHartmut Knaack #define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0) 525dbbd19fSMartin Fuzzey #define MMA8452_TRANSIENT_COUNT 0x20 53c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG1 0x2a 5469abff81SHartmut Knaack #define MMA8452_CTRL_ACTIVE BIT(0) 5569abff81SHartmut Knaack #define MMA8452_CTRL_DR_MASK GENMASK(5, 3) 5669abff81SHartmut Knaack #define MMA8452_CTRL_DR_SHIFT 3 5769abff81SHartmut Knaack #define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ 58c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG2 0x2b 59ecabae71SMartin Fuzzey #define MMA8452_CTRL_REG2_RST BIT(6) 6028e34278SMartin Fuzzey #define MMA8452_CTRL_REG4 0x2d 6128e34278SMartin Fuzzey #define MMA8452_CTRL_REG5 0x2e 6269abff81SHartmut Knaack #define MMA8452_OFF_X 0x2f 6369abff81SHartmut Knaack #define MMA8452_OFF_Y 0x30 6469abff81SHartmut Knaack #define MMA8452_OFF_Z 0x31 65c7eeea93SPeter Meerwald 662a17698cSMartin Fuzzey #define MMA8452_MAX_REG 0x31 672a17698cSMartin Fuzzey 68ae6d9ce0SMartin Fuzzey #define MMA8452_INT_DRDY BIT(0) 6928e34278SMartin Fuzzey #define MMA8452_INT_TRANS BIT(5) 7028e34278SMartin Fuzzey 71c7eeea93SPeter Meerwald #define MMA8452_DEVICE_ID 0x2a 72c7eeea93SPeter Meerwald 73c7eeea93SPeter Meerwald struct mma8452_data { 74c7eeea93SPeter Meerwald struct i2c_client *client; 75c7eeea93SPeter Meerwald struct mutex lock; 76c7eeea93SPeter Meerwald u8 ctrl_reg1; 77c7eeea93SPeter Meerwald u8 data_cfg; 78*c3cdd6e4SMartin Kepplinger const struct mma_chip_info *chip_info; 79*c3cdd6e4SMartin Kepplinger }; 80*c3cdd6e4SMartin Kepplinger 81*c3cdd6e4SMartin Kepplinger /** 82*c3cdd6e4SMartin Kepplinger * struct mma_chip_info - chip specific data for Freescale's accelerometers 83*c3cdd6e4SMartin Kepplinger * @chip_id: WHO_AM_I register's value 84*c3cdd6e4SMartin Kepplinger * @channels: struct iio_chan_spec matching the device's 85*c3cdd6e4SMartin Kepplinger * capabilities 86*c3cdd6e4SMartin Kepplinger * @num_channels: number of channels 87*c3cdd6e4SMartin Kepplinger * @mma_scales: scale factors for converting register values 88*c3cdd6e4SMartin Kepplinger * to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers 89*c3cdd6e4SMartin Kepplinger * per mode: m/s^2 and micro m/s^2 90*c3cdd6e4SMartin Kepplinger * @ev_cfg: event config register address 91*c3cdd6e4SMartin Kepplinger * @ev_cfg_ele: latch bit in event config register 92*c3cdd6e4SMartin Kepplinger * @ev_cfg_chan_shift: number of the bit to enable events in X 93*c3cdd6e4SMartin Kepplinger * direction; in event config register 94*c3cdd6e4SMartin Kepplinger * @ev_src: event source register address 95*c3cdd6e4SMartin Kepplinger * @ev_src_xe: bit in event source register that indicates 96*c3cdd6e4SMartin Kepplinger * an event in X direction 97*c3cdd6e4SMartin Kepplinger * @ev_src_ye: bit in event source register that indicates 98*c3cdd6e4SMartin Kepplinger * an event in Y direction 99*c3cdd6e4SMartin Kepplinger * @ev_src_ze: bit in event source register that indicates 100*c3cdd6e4SMartin Kepplinger * an event in Z direction 101*c3cdd6e4SMartin Kepplinger * @ev_ths: event threshold register address 102*c3cdd6e4SMartin Kepplinger * @ev_ths_mask: mask for the threshold value 103*c3cdd6e4SMartin Kepplinger * @ev_count: event count (period) register address 104*c3cdd6e4SMartin Kepplinger * 105*c3cdd6e4SMartin Kepplinger * Since not all chips supported by the driver support comparing high pass 106*c3cdd6e4SMartin Kepplinger * filtered data for events (interrupts), different interrupt sources are 107*c3cdd6e4SMartin Kepplinger * used for different chips and the relevant registers are included here. 108*c3cdd6e4SMartin Kepplinger */ 109*c3cdd6e4SMartin Kepplinger struct mma_chip_info { 110*c3cdd6e4SMartin Kepplinger u8 chip_id; 111*c3cdd6e4SMartin Kepplinger const struct iio_chan_spec *channels; 112*c3cdd6e4SMartin Kepplinger int num_channels; 113*c3cdd6e4SMartin Kepplinger const int mma_scales[3][2]; 114*c3cdd6e4SMartin Kepplinger u8 ev_cfg; 115*c3cdd6e4SMartin Kepplinger u8 ev_cfg_ele; 116*c3cdd6e4SMartin Kepplinger u8 ev_cfg_chan_shift; 117*c3cdd6e4SMartin Kepplinger u8 ev_src; 118*c3cdd6e4SMartin Kepplinger u8 ev_src_xe; 119*c3cdd6e4SMartin Kepplinger u8 ev_src_ye; 120*c3cdd6e4SMartin Kepplinger u8 ev_src_ze; 121*c3cdd6e4SMartin Kepplinger u8 ev_ths; 122*c3cdd6e4SMartin Kepplinger u8 ev_ths_mask; 123*c3cdd6e4SMartin Kepplinger u8 ev_count; 124c7eeea93SPeter Meerwald }; 125c7eeea93SPeter Meerwald 126c7eeea93SPeter Meerwald static int mma8452_drdy(struct mma8452_data *data) 127c7eeea93SPeter Meerwald { 128c7eeea93SPeter Meerwald int tries = 150; 129c7eeea93SPeter Meerwald 130c7eeea93SPeter Meerwald while (tries-- > 0) { 131c7eeea93SPeter Meerwald int ret = i2c_smbus_read_byte_data(data->client, 132c7eeea93SPeter Meerwald MMA8452_STATUS); 133c7eeea93SPeter Meerwald if (ret < 0) 134c7eeea93SPeter Meerwald return ret; 135c7eeea93SPeter Meerwald if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) 136c7eeea93SPeter Meerwald return 0; 137686027fbSHartmut Knaack 138c7eeea93SPeter Meerwald msleep(20); 139c7eeea93SPeter Meerwald } 140c7eeea93SPeter Meerwald 141c7eeea93SPeter Meerwald dev_err(&data->client->dev, "data not ready\n"); 142686027fbSHartmut Knaack 143c7eeea93SPeter Meerwald return -EIO; 144c7eeea93SPeter Meerwald } 145c7eeea93SPeter Meerwald 146c7eeea93SPeter Meerwald static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) 147c7eeea93SPeter Meerwald { 148c7eeea93SPeter Meerwald int ret = mma8452_drdy(data); 149686027fbSHartmut Knaack 150c7eeea93SPeter Meerwald if (ret < 0) 151c7eeea93SPeter Meerwald return ret; 152686027fbSHartmut Knaack 153686027fbSHartmut Knaack return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X, 154686027fbSHartmut Knaack 3 * sizeof(__be16), (u8 *)buf); 155c7eeea93SPeter Meerwald } 156c7eeea93SPeter Meerwald 157686027fbSHartmut Knaack static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2], 158686027fbSHartmut Knaack int n) 159c7eeea93SPeter Meerwald { 160c7eeea93SPeter Meerwald size_t len = 0; 161c7eeea93SPeter Meerwald 162c7eeea93SPeter Meerwald while (n-- > 0) 163686027fbSHartmut Knaack len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", 164686027fbSHartmut Knaack vals[n][0], vals[n][1]); 165c7eeea93SPeter Meerwald 166c7eeea93SPeter Meerwald /* replace trailing space by newline */ 167c7eeea93SPeter Meerwald buf[len - 1] = '\n'; 168c7eeea93SPeter Meerwald 169c7eeea93SPeter Meerwald return len; 170c7eeea93SPeter Meerwald } 171c7eeea93SPeter Meerwald 172c7eeea93SPeter Meerwald static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n, 173c7eeea93SPeter Meerwald int val, int val2) 174c7eeea93SPeter Meerwald { 175c7eeea93SPeter Meerwald while (n-- > 0) 176c7eeea93SPeter Meerwald if (val == vals[n][0] && val2 == vals[n][1]) 177c7eeea93SPeter Meerwald return n; 178c7eeea93SPeter Meerwald 179c7eeea93SPeter Meerwald return -EINVAL; 180c7eeea93SPeter Meerwald } 181c7eeea93SPeter Meerwald 1825dbbd19fSMartin Fuzzey static int mma8452_get_odr_index(struct mma8452_data *data) 1835dbbd19fSMartin Fuzzey { 1845dbbd19fSMartin Fuzzey return (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >> 1855dbbd19fSMartin Fuzzey MMA8452_CTRL_DR_SHIFT; 1865dbbd19fSMartin Fuzzey } 1875dbbd19fSMartin Fuzzey 188c7eeea93SPeter Meerwald static const int mma8452_samp_freq[8][2] = { 189c7eeea93SPeter Meerwald {800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000}, 190c7eeea93SPeter Meerwald {6, 250000}, {1, 560000} 191c7eeea93SPeter Meerwald }; 192c7eeea93SPeter Meerwald 1935dbbd19fSMartin Fuzzey /* Datasheet table 35 (step time vs sample frequency) */ 1945dbbd19fSMartin Fuzzey static const int mma8452_transient_time_step_us[8] = { 1955dbbd19fSMartin Fuzzey 1250, 1965dbbd19fSMartin Fuzzey 2500, 1975dbbd19fSMartin Fuzzey 5000, 1985dbbd19fSMartin Fuzzey 10000, 1995dbbd19fSMartin Fuzzey 20000, 2005dbbd19fSMartin Fuzzey 20000, 2015dbbd19fSMartin Fuzzey 20000, 2025dbbd19fSMartin Fuzzey 20000 2035dbbd19fSMartin Fuzzey }; 2045dbbd19fSMartin Fuzzey 2051e79841aSMartin Fuzzey /* Datasheet table 18 (normal mode) */ 2061e79841aSMartin Fuzzey static const int mma8452_hp_filter_cutoff[8][4][2] = { 2071e79841aSMartin Fuzzey { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 800 Hz sample */ 2081e79841aSMartin Fuzzey { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 400 Hz sample */ 2091e79841aSMartin Fuzzey { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, /* 200 Hz sample */ 2101e79841aSMartin Fuzzey { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, /* 100 Hz sample */ 2111e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 50 Hz sample */ 2121e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 12.5 Hz sample */ 2131e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 6.25 Hz sample */ 2141e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} } /* 1.56 Hz sample */ 2151e79841aSMartin Fuzzey }; 2161e79841aSMartin Fuzzey 217c7eeea93SPeter Meerwald static ssize_t mma8452_show_samp_freq_avail(struct device *dev, 218686027fbSHartmut Knaack struct device_attribute *attr, 219686027fbSHartmut Knaack char *buf) 220c7eeea93SPeter Meerwald { 221c7eeea93SPeter Meerwald return mma8452_show_int_plus_micros(buf, mma8452_samp_freq, 222c7eeea93SPeter Meerwald ARRAY_SIZE(mma8452_samp_freq)); 223c7eeea93SPeter Meerwald } 224c7eeea93SPeter Meerwald 225c7eeea93SPeter Meerwald static ssize_t mma8452_show_scale_avail(struct device *dev, 226686027fbSHartmut Knaack struct device_attribute *attr, 227686027fbSHartmut Knaack char *buf) 228c7eeea93SPeter Meerwald { 229*c3cdd6e4SMartin Kepplinger struct mma8452_data *data = iio_priv(i2c_get_clientdata( 230*c3cdd6e4SMartin Kepplinger to_i2c_client(dev))); 231*c3cdd6e4SMartin Kepplinger 232*c3cdd6e4SMartin Kepplinger return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales, 233*c3cdd6e4SMartin Kepplinger ARRAY_SIZE(data->chip_info->mma_scales)); 234c7eeea93SPeter Meerwald } 235c7eeea93SPeter Meerwald 2361e79841aSMartin Fuzzey static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, 2371e79841aSMartin Fuzzey struct device_attribute *attr, 2381e79841aSMartin Fuzzey char *buf) 2391e79841aSMartin Fuzzey { 2401e79841aSMartin Fuzzey struct iio_dev *indio_dev = dev_to_iio_dev(dev); 2411e79841aSMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 2421e79841aSMartin Fuzzey int i = mma8452_get_odr_index(data); 2431e79841aSMartin Fuzzey 2441e79841aSMartin Fuzzey return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[i], 2451e79841aSMartin Fuzzey ARRAY_SIZE(mma8452_hp_filter_cutoff[0])); 2461e79841aSMartin Fuzzey } 2471e79841aSMartin Fuzzey 248c7eeea93SPeter Meerwald static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); 249c7eeea93SPeter Meerwald static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO, 250c7eeea93SPeter Meerwald mma8452_show_scale_avail, NULL, 0); 2511e79841aSMartin Fuzzey static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available, 2521e79841aSMartin Fuzzey S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); 253c7eeea93SPeter Meerwald 254c7eeea93SPeter Meerwald static int mma8452_get_samp_freq_index(struct mma8452_data *data, 255c7eeea93SPeter Meerwald int val, int val2) 256c7eeea93SPeter Meerwald { 257c7eeea93SPeter Meerwald return mma8452_get_int_plus_micros_index(mma8452_samp_freq, 258686027fbSHartmut Knaack ARRAY_SIZE(mma8452_samp_freq), 259686027fbSHartmut Knaack val, val2); 260c7eeea93SPeter Meerwald } 261c7eeea93SPeter Meerwald 262686027fbSHartmut Knaack static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) 263c7eeea93SPeter Meerwald { 264*c3cdd6e4SMartin Kepplinger return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales, 265*c3cdd6e4SMartin Kepplinger ARRAY_SIZE(data->chip_info->mma_scales), val, val2); 266c7eeea93SPeter Meerwald } 267c7eeea93SPeter Meerwald 2681e79841aSMartin Fuzzey static int mma8452_get_hp_filter_index(struct mma8452_data *data, 2691e79841aSMartin Fuzzey int val, int val2) 2701e79841aSMartin Fuzzey { 2711e79841aSMartin Fuzzey int i = mma8452_get_odr_index(data); 2721e79841aSMartin Fuzzey 2731e79841aSMartin Fuzzey return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i], 274001fceb9SHartmut Knaack ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2); 2751e79841aSMartin Fuzzey } 2761e79841aSMartin Fuzzey 2771e79841aSMartin Fuzzey static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz) 2781e79841aSMartin Fuzzey { 2791e79841aSMartin Fuzzey int i, ret; 2801e79841aSMartin Fuzzey 2811e79841aSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); 2821e79841aSMartin Fuzzey if (ret < 0) 2831e79841aSMartin Fuzzey return ret; 2841e79841aSMartin Fuzzey 2851e79841aSMartin Fuzzey i = mma8452_get_odr_index(data); 2861e79841aSMartin Fuzzey ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK; 2871e79841aSMartin Fuzzey *hz = mma8452_hp_filter_cutoff[i][ret][0]; 2881e79841aSMartin Fuzzey *uHz = mma8452_hp_filter_cutoff[i][ret][1]; 2891e79841aSMartin Fuzzey 2901e79841aSMartin Fuzzey return 0; 2911e79841aSMartin Fuzzey } 2921e79841aSMartin Fuzzey 293c7eeea93SPeter Meerwald static int mma8452_read_raw(struct iio_dev *indio_dev, 294c7eeea93SPeter Meerwald struct iio_chan_spec const *chan, 295c7eeea93SPeter Meerwald int *val, int *val2, long mask) 296c7eeea93SPeter Meerwald { 297c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 298c7eeea93SPeter Meerwald __be16 buffer[3]; 299c7eeea93SPeter Meerwald int i, ret; 300c7eeea93SPeter Meerwald 301c7eeea93SPeter Meerwald switch (mask) { 302c7eeea93SPeter Meerwald case IIO_CHAN_INFO_RAW: 303c7eeea93SPeter Meerwald if (iio_buffer_enabled(indio_dev)) 304c7eeea93SPeter Meerwald return -EBUSY; 305c7eeea93SPeter Meerwald 306c7eeea93SPeter Meerwald mutex_lock(&data->lock); 307c7eeea93SPeter Meerwald ret = mma8452_read(data, buffer); 308c7eeea93SPeter Meerwald mutex_unlock(&data->lock); 309c7eeea93SPeter Meerwald if (ret < 0) 310c7eeea93SPeter Meerwald return ret; 311686027fbSHartmut Knaack 312*c3cdd6e4SMartin Kepplinger *val = sign_extend32(be16_to_cpu( 313*c3cdd6e4SMartin Kepplinger buffer[chan->scan_index]) >> chan->scan_type.shift, 314*c3cdd6e4SMartin Kepplinger chan->scan_type.realbits - 1); 315686027fbSHartmut Knaack 316c7eeea93SPeter Meerwald return IIO_VAL_INT; 317c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SCALE: 318c7eeea93SPeter Meerwald i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; 319*c3cdd6e4SMartin Kepplinger *val = data->chip_info->mma_scales[i][0]; 320*c3cdd6e4SMartin Kepplinger *val2 = data->chip_info->mma_scales[i][1]; 321686027fbSHartmut Knaack 322c7eeea93SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 323c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SAMP_FREQ: 3245dbbd19fSMartin Fuzzey i = mma8452_get_odr_index(data); 325c7eeea93SPeter Meerwald *val = mma8452_samp_freq[i][0]; 326c7eeea93SPeter Meerwald *val2 = mma8452_samp_freq[i][1]; 327686027fbSHartmut Knaack 328c7eeea93SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 329c7eeea93SPeter Meerwald case IIO_CHAN_INFO_CALIBBIAS: 330686027fbSHartmut Knaack ret = i2c_smbus_read_byte_data(data->client, 331686027fbSHartmut Knaack MMA8452_OFF_X + chan->scan_index); 332c7eeea93SPeter Meerwald if (ret < 0) 333c7eeea93SPeter Meerwald return ret; 334686027fbSHartmut Knaack 335c7eeea93SPeter Meerwald *val = sign_extend32(ret, 7); 336686027fbSHartmut Knaack 337c7eeea93SPeter Meerwald return IIO_VAL_INT; 3381e79841aSMartin Fuzzey case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 3391e79841aSMartin Fuzzey if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) { 3401e79841aSMartin Fuzzey ret = mma8452_read_hp_filter(data, val, val2); 3411e79841aSMartin Fuzzey if (ret < 0) 3421e79841aSMartin Fuzzey return ret; 3431e79841aSMartin Fuzzey } else { 3441e79841aSMartin Fuzzey *val = 0; 3451e79841aSMartin Fuzzey *val2 = 0; 3461e79841aSMartin Fuzzey } 347686027fbSHartmut Knaack 3481e79841aSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 349c7eeea93SPeter Meerwald } 350686027fbSHartmut Knaack 351c7eeea93SPeter Meerwald return -EINVAL; 352c7eeea93SPeter Meerwald } 353c7eeea93SPeter Meerwald 354c7eeea93SPeter Meerwald static int mma8452_standby(struct mma8452_data *data) 355c7eeea93SPeter Meerwald { 356c7eeea93SPeter Meerwald return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, 357c7eeea93SPeter Meerwald data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); 358c7eeea93SPeter Meerwald } 359c7eeea93SPeter Meerwald 360c7eeea93SPeter Meerwald static int mma8452_active(struct mma8452_data *data) 361c7eeea93SPeter Meerwald { 362c7eeea93SPeter Meerwald return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, 363c7eeea93SPeter Meerwald data->ctrl_reg1); 364c7eeea93SPeter Meerwald } 365c7eeea93SPeter Meerwald 366c7eeea93SPeter Meerwald static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) 367c7eeea93SPeter Meerwald { 368c7eeea93SPeter Meerwald int ret; 369c7eeea93SPeter Meerwald 370c7eeea93SPeter Meerwald mutex_lock(&data->lock); 371c7eeea93SPeter Meerwald 372c7eeea93SPeter Meerwald /* config can only be changed when in standby */ 373c7eeea93SPeter Meerwald ret = mma8452_standby(data); 374c7eeea93SPeter Meerwald if (ret < 0) 375c7eeea93SPeter Meerwald goto fail; 376c7eeea93SPeter Meerwald 377c7eeea93SPeter Meerwald ret = i2c_smbus_write_byte_data(data->client, reg, val); 378c7eeea93SPeter Meerwald if (ret < 0) 379c7eeea93SPeter Meerwald goto fail; 380c7eeea93SPeter Meerwald 381c7eeea93SPeter Meerwald ret = mma8452_active(data); 382c7eeea93SPeter Meerwald if (ret < 0) 383c7eeea93SPeter Meerwald goto fail; 384c7eeea93SPeter Meerwald 385c7eeea93SPeter Meerwald ret = 0; 386c7eeea93SPeter Meerwald fail: 387c7eeea93SPeter Meerwald mutex_unlock(&data->lock); 388686027fbSHartmut Knaack 389c7eeea93SPeter Meerwald return ret; 390c7eeea93SPeter Meerwald } 391c7eeea93SPeter Meerwald 3921e79841aSMartin Fuzzey static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, 3931e79841aSMartin Fuzzey int val, int val2) 3941e79841aSMartin Fuzzey { 3951e79841aSMartin Fuzzey int i, reg; 3961e79841aSMartin Fuzzey 3971e79841aSMartin Fuzzey i = mma8452_get_hp_filter_index(data, val, val2); 3981e79841aSMartin Fuzzey if (i < 0) 399b9fddcdbSHartmut Knaack return i; 4001e79841aSMartin Fuzzey 4011e79841aSMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, 4021e79841aSMartin Fuzzey MMA8452_HP_FILTER_CUTOFF); 4031e79841aSMartin Fuzzey if (reg < 0) 4041e79841aSMartin Fuzzey return reg; 405686027fbSHartmut Knaack 4061e79841aSMartin Fuzzey reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK; 4071e79841aSMartin Fuzzey reg |= i; 4081e79841aSMartin Fuzzey 4091e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg); 4101e79841aSMartin Fuzzey } 4111e79841aSMartin Fuzzey 412c7eeea93SPeter Meerwald static int mma8452_write_raw(struct iio_dev *indio_dev, 413c7eeea93SPeter Meerwald struct iio_chan_spec const *chan, 414c7eeea93SPeter Meerwald int val, int val2, long mask) 415c7eeea93SPeter Meerwald { 416c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 4171e79841aSMartin Fuzzey int i, ret; 418c7eeea93SPeter Meerwald 419c7eeea93SPeter Meerwald if (iio_buffer_enabled(indio_dev)) 420c7eeea93SPeter Meerwald return -EBUSY; 421c7eeea93SPeter Meerwald 422c7eeea93SPeter Meerwald switch (mask) { 423c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SAMP_FREQ: 424c7eeea93SPeter Meerwald i = mma8452_get_samp_freq_index(data, val, val2); 425c7eeea93SPeter Meerwald if (i < 0) 426b9fddcdbSHartmut Knaack return i; 427c7eeea93SPeter Meerwald 428c7eeea93SPeter Meerwald data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; 429c7eeea93SPeter Meerwald data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; 430686027fbSHartmut Knaack 431c7eeea93SPeter Meerwald return mma8452_change_config(data, MMA8452_CTRL_REG1, 432c7eeea93SPeter Meerwald data->ctrl_reg1); 433c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SCALE: 434c7eeea93SPeter Meerwald i = mma8452_get_scale_index(data, val, val2); 435c7eeea93SPeter Meerwald if (i < 0) 436b9fddcdbSHartmut Knaack return i; 437686027fbSHartmut Knaack 438c7eeea93SPeter Meerwald data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; 439c7eeea93SPeter Meerwald data->data_cfg |= i; 440686027fbSHartmut Knaack 441c7eeea93SPeter Meerwald return mma8452_change_config(data, MMA8452_DATA_CFG, 442c7eeea93SPeter Meerwald data->data_cfg); 443c7eeea93SPeter Meerwald case IIO_CHAN_INFO_CALIBBIAS: 444c7eeea93SPeter Meerwald if (val < -128 || val > 127) 445c7eeea93SPeter Meerwald return -EINVAL; 446686027fbSHartmut Knaack 447686027fbSHartmut Knaack return mma8452_change_config(data, 448686027fbSHartmut Knaack MMA8452_OFF_X + chan->scan_index, 449686027fbSHartmut Knaack val); 4501e79841aSMartin Fuzzey 4511e79841aSMartin Fuzzey case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 4521e79841aSMartin Fuzzey if (val == 0 && val2 == 0) { 4531e79841aSMartin Fuzzey data->data_cfg &= ~MMA8452_DATA_CFG_HPF_MASK; 4541e79841aSMartin Fuzzey } else { 4551e79841aSMartin Fuzzey data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK; 4561e79841aSMartin Fuzzey ret = mma8452_set_hp_filter_frequency(data, val, val2); 4571e79841aSMartin Fuzzey if (ret < 0) 4581e79841aSMartin Fuzzey return ret; 4591e79841aSMartin Fuzzey } 460686027fbSHartmut Knaack 4611e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_DATA_CFG, 4621e79841aSMartin Fuzzey data->data_cfg); 4631e79841aSMartin Fuzzey 464c7eeea93SPeter Meerwald default: 465c7eeea93SPeter Meerwald return -EINVAL; 466c7eeea93SPeter Meerwald } 467c7eeea93SPeter Meerwald } 468c7eeea93SPeter Meerwald 46928e34278SMartin Fuzzey static int mma8452_read_thresh(struct iio_dev *indio_dev, 47028e34278SMartin Fuzzey const struct iio_chan_spec *chan, 47128e34278SMartin Fuzzey enum iio_event_type type, 47228e34278SMartin Fuzzey enum iio_event_direction dir, 47328e34278SMartin Fuzzey enum iio_event_info info, 47428e34278SMartin Fuzzey int *val, int *val2) 47528e34278SMartin Fuzzey { 47628e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 4775dbbd19fSMartin Fuzzey int ret, us; 47828e34278SMartin Fuzzey 4795dbbd19fSMartin Fuzzey switch (info) { 4805dbbd19fSMartin Fuzzey case IIO_EV_INFO_VALUE: 4815dbbd19fSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, 482*c3cdd6e4SMartin Kepplinger data->chip_info->ev_ths); 48328e34278SMartin Fuzzey if (ret < 0) 48428e34278SMartin Fuzzey return ret; 48528e34278SMartin Fuzzey 486*c3cdd6e4SMartin Kepplinger *val = ret & data->chip_info->ev_ths_mask; 487686027fbSHartmut Knaack 48828e34278SMartin Fuzzey return IIO_VAL_INT; 4895dbbd19fSMartin Fuzzey 4905dbbd19fSMartin Fuzzey case IIO_EV_INFO_PERIOD: 4915dbbd19fSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, 492*c3cdd6e4SMartin Kepplinger data->chip_info->ev_count); 4935dbbd19fSMartin Fuzzey if (ret < 0) 4945dbbd19fSMartin Fuzzey return ret; 4955dbbd19fSMartin Fuzzey 4965dbbd19fSMartin Fuzzey us = ret * mma8452_transient_time_step_us[ 4975dbbd19fSMartin Fuzzey mma8452_get_odr_index(data)]; 4985dbbd19fSMartin Fuzzey *val = us / USEC_PER_SEC; 4995dbbd19fSMartin Fuzzey *val2 = us % USEC_PER_SEC; 500686027fbSHartmut Knaack 5015dbbd19fSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 5025dbbd19fSMartin Fuzzey 5031e79841aSMartin Fuzzey case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: 5041e79841aSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, 5051e79841aSMartin Fuzzey MMA8452_TRANSIENT_CFG); 5061e79841aSMartin Fuzzey if (ret < 0) 5071e79841aSMartin Fuzzey return ret; 5081e79841aSMartin Fuzzey 5091e79841aSMartin Fuzzey if (ret & MMA8452_TRANSIENT_CFG_HPF_BYP) { 5101e79841aSMartin Fuzzey *val = 0; 5111e79841aSMartin Fuzzey *val2 = 0; 5121e79841aSMartin Fuzzey } else { 5131e79841aSMartin Fuzzey ret = mma8452_read_hp_filter(data, val, val2); 5141e79841aSMartin Fuzzey if (ret < 0) 5151e79841aSMartin Fuzzey return ret; 5161e79841aSMartin Fuzzey } 517686027fbSHartmut Knaack 5181e79841aSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 5191e79841aSMartin Fuzzey 5205dbbd19fSMartin Fuzzey default: 5215dbbd19fSMartin Fuzzey return -EINVAL; 5225dbbd19fSMartin Fuzzey } 52328e34278SMartin Fuzzey } 52428e34278SMartin Fuzzey 52528e34278SMartin Fuzzey static int mma8452_write_thresh(struct iio_dev *indio_dev, 52628e34278SMartin Fuzzey const struct iio_chan_spec *chan, 52728e34278SMartin Fuzzey enum iio_event_type type, 52828e34278SMartin Fuzzey enum iio_event_direction dir, 52928e34278SMartin Fuzzey enum iio_event_info info, 53028e34278SMartin Fuzzey int val, int val2) 53128e34278SMartin Fuzzey { 53228e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 5331e79841aSMartin Fuzzey int ret, reg, steps; 53428e34278SMartin Fuzzey 5355dbbd19fSMartin Fuzzey switch (info) { 5365dbbd19fSMartin Fuzzey case IIO_EV_INFO_VALUE: 53711218226SHartmut Knaack if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK) 53811218226SHartmut Knaack return -EINVAL; 53911218226SHartmut Knaack 540*c3cdd6e4SMartin Kepplinger return mma8452_change_config(data, data->chip_info->ev_ths, 541*c3cdd6e4SMartin Kepplinger val); 5425dbbd19fSMartin Fuzzey 5435dbbd19fSMartin Fuzzey case IIO_EV_INFO_PERIOD: 5445dbbd19fSMartin Fuzzey steps = (val * USEC_PER_SEC + val2) / 5455dbbd19fSMartin Fuzzey mma8452_transient_time_step_us[ 5465dbbd19fSMartin Fuzzey mma8452_get_odr_index(data)]; 5475dbbd19fSMartin Fuzzey 54811218226SHartmut Knaack if (steps < 0 || steps > 0xff) 5495dbbd19fSMartin Fuzzey return -EINVAL; 5505dbbd19fSMartin Fuzzey 551*c3cdd6e4SMartin Kepplinger return mma8452_change_config(data, data->chip_info->ev_count, 5525dbbd19fSMartin Fuzzey steps); 553686027fbSHartmut Knaack 5541e79841aSMartin Fuzzey case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: 5551e79841aSMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, 5561e79841aSMartin Fuzzey MMA8452_TRANSIENT_CFG); 5571e79841aSMartin Fuzzey if (reg < 0) 5581e79841aSMartin Fuzzey return reg; 5591e79841aSMartin Fuzzey 5601e79841aSMartin Fuzzey if (val == 0 && val2 == 0) { 5611e79841aSMartin Fuzzey reg |= MMA8452_TRANSIENT_CFG_HPF_BYP; 5621e79841aSMartin Fuzzey } else { 5631e79841aSMartin Fuzzey reg &= ~MMA8452_TRANSIENT_CFG_HPF_BYP; 5641e79841aSMartin Fuzzey ret = mma8452_set_hp_filter_frequency(data, val, val2); 5651e79841aSMartin Fuzzey if (ret < 0) 5661e79841aSMartin Fuzzey return ret; 5671e79841aSMartin Fuzzey } 568686027fbSHartmut Knaack 5691e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg); 5701e79841aSMartin Fuzzey 5715dbbd19fSMartin Fuzzey default: 5725dbbd19fSMartin Fuzzey return -EINVAL; 5735dbbd19fSMartin Fuzzey } 57428e34278SMartin Fuzzey } 57528e34278SMartin Fuzzey 57628e34278SMartin Fuzzey static int mma8452_read_event_config(struct iio_dev *indio_dev, 57728e34278SMartin Fuzzey const struct iio_chan_spec *chan, 57828e34278SMartin Fuzzey enum iio_event_type type, 57928e34278SMartin Fuzzey enum iio_event_direction dir) 58028e34278SMartin Fuzzey { 58128e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 582*c3cdd6e4SMartin Kepplinger const struct mma_chip_info *chip = data->chip_info; 58328e34278SMartin Fuzzey int ret; 58428e34278SMartin Fuzzey 585*c3cdd6e4SMartin Kepplinger ret = i2c_smbus_read_byte_data(data->client, 586*c3cdd6e4SMartin Kepplinger data->chip_info->ev_cfg); 58728e34278SMartin Fuzzey if (ret < 0) 58828e34278SMartin Fuzzey return ret; 58928e34278SMartin Fuzzey 590*c3cdd6e4SMartin Kepplinger return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift)); 59128e34278SMartin Fuzzey } 59228e34278SMartin Fuzzey 59328e34278SMartin Fuzzey static int mma8452_write_event_config(struct iio_dev *indio_dev, 59428e34278SMartin Fuzzey const struct iio_chan_spec *chan, 59528e34278SMartin Fuzzey enum iio_event_type type, 59628e34278SMartin Fuzzey enum iio_event_direction dir, 59728e34278SMartin Fuzzey int state) 59828e34278SMartin Fuzzey { 59928e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 600*c3cdd6e4SMartin Kepplinger const struct mma_chip_info *chip = data->chip_info; 60128e34278SMartin Fuzzey int val; 60228e34278SMartin Fuzzey 603*c3cdd6e4SMartin Kepplinger val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg); 60428e34278SMartin Fuzzey if (val < 0) 60528e34278SMartin Fuzzey return val; 60628e34278SMartin Fuzzey 60728e34278SMartin Fuzzey if (state) 608*c3cdd6e4SMartin Kepplinger val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift); 60928e34278SMartin Fuzzey else 610*c3cdd6e4SMartin Kepplinger val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift); 61128e34278SMartin Fuzzey 61228e34278SMartin Fuzzey val |= MMA8452_TRANSIENT_CFG_ELE; 61328e34278SMartin Fuzzey 614*c3cdd6e4SMartin Kepplinger return mma8452_change_config(data, chip->ev_cfg, val); 61528e34278SMartin Fuzzey } 61628e34278SMartin Fuzzey 61728e34278SMartin Fuzzey static void mma8452_transient_interrupt(struct iio_dev *indio_dev) 61828e34278SMartin Fuzzey { 61928e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 62028e34278SMartin Fuzzey s64 ts = iio_get_time_ns(); 62128e34278SMartin Fuzzey int src; 62228e34278SMartin Fuzzey 623*c3cdd6e4SMartin Kepplinger src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src); 62428e34278SMartin Fuzzey if (src < 0) 62528e34278SMartin Fuzzey return; 62628e34278SMartin Fuzzey 627*c3cdd6e4SMartin Kepplinger if (src & data->chip_info->ev_src_xe) 62828e34278SMartin Fuzzey iio_push_event(indio_dev, 62928e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, 630c5d0db06SMartin Kepplinger IIO_EV_TYPE_MAG, 63128e34278SMartin Fuzzey IIO_EV_DIR_RISING), 63228e34278SMartin Fuzzey ts); 63328e34278SMartin Fuzzey 634*c3cdd6e4SMartin Kepplinger if (src & data->chip_info->ev_src_ye) 63528e34278SMartin Fuzzey iio_push_event(indio_dev, 63628e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y, 637c5d0db06SMartin Kepplinger IIO_EV_TYPE_MAG, 63828e34278SMartin Fuzzey IIO_EV_DIR_RISING), 63928e34278SMartin Fuzzey ts); 64028e34278SMartin Fuzzey 641*c3cdd6e4SMartin Kepplinger if (src & data->chip_info->ev_src_ze) 64228e34278SMartin Fuzzey iio_push_event(indio_dev, 64328e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z, 644c5d0db06SMartin Kepplinger IIO_EV_TYPE_MAG, 64528e34278SMartin Fuzzey IIO_EV_DIR_RISING), 64628e34278SMartin Fuzzey ts); 64728e34278SMartin Fuzzey } 64828e34278SMartin Fuzzey 64928e34278SMartin Fuzzey static irqreturn_t mma8452_interrupt(int irq, void *p) 65028e34278SMartin Fuzzey { 65128e34278SMartin Fuzzey struct iio_dev *indio_dev = p; 65228e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 653ae6d9ce0SMartin Fuzzey int ret = IRQ_NONE; 65428e34278SMartin Fuzzey int src; 65528e34278SMartin Fuzzey 65628e34278SMartin Fuzzey src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC); 65728e34278SMartin Fuzzey if (src < 0) 65828e34278SMartin Fuzzey return IRQ_NONE; 65928e34278SMartin Fuzzey 660ae6d9ce0SMartin Fuzzey if (src & MMA8452_INT_DRDY) { 661ae6d9ce0SMartin Fuzzey iio_trigger_poll_chained(indio_dev->trig); 662ae6d9ce0SMartin Fuzzey ret = IRQ_HANDLED; 66328e34278SMartin Fuzzey } 66428e34278SMartin Fuzzey 665ae6d9ce0SMartin Fuzzey if (src & MMA8452_INT_TRANS) { 666ae6d9ce0SMartin Fuzzey mma8452_transient_interrupt(indio_dev); 667ae6d9ce0SMartin Fuzzey ret = IRQ_HANDLED; 668ae6d9ce0SMartin Fuzzey } 669ae6d9ce0SMartin Fuzzey 670ae6d9ce0SMartin Fuzzey return ret; 67128e34278SMartin Fuzzey } 67228e34278SMartin Fuzzey 673c7eeea93SPeter Meerwald static irqreturn_t mma8452_trigger_handler(int irq, void *p) 674c7eeea93SPeter Meerwald { 675c7eeea93SPeter Meerwald struct iio_poll_func *pf = p; 676c7eeea93SPeter Meerwald struct iio_dev *indio_dev = pf->indio_dev; 677c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 678c7eeea93SPeter Meerwald u8 buffer[16]; /* 3 16-bit channels + padding + ts */ 679c7eeea93SPeter Meerwald int ret; 680c7eeea93SPeter Meerwald 681c7eeea93SPeter Meerwald ret = mma8452_read(data, (__be16 *)buffer); 682c7eeea93SPeter Meerwald if (ret < 0) 683c7eeea93SPeter Meerwald goto done; 684c7eeea93SPeter Meerwald 685c7eeea93SPeter Meerwald iio_push_to_buffers_with_timestamp(indio_dev, buffer, 686c7eeea93SPeter Meerwald iio_get_time_ns()); 687c7eeea93SPeter Meerwald 688c7eeea93SPeter Meerwald done: 689c7eeea93SPeter Meerwald iio_trigger_notify_done(indio_dev->trig); 690686027fbSHartmut Knaack 691c7eeea93SPeter Meerwald return IRQ_HANDLED; 692c7eeea93SPeter Meerwald } 693c7eeea93SPeter Meerwald 6942a17698cSMartin Fuzzey static int mma8452_reg_access_dbg(struct iio_dev *indio_dev, 6952a17698cSMartin Fuzzey unsigned reg, unsigned writeval, 6962a17698cSMartin Fuzzey unsigned *readval) 6972a17698cSMartin Fuzzey { 6982a17698cSMartin Fuzzey int ret; 6992a17698cSMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 7002a17698cSMartin Fuzzey 7012a17698cSMartin Fuzzey if (reg > MMA8452_MAX_REG) 7022a17698cSMartin Fuzzey return -EINVAL; 7032a17698cSMartin Fuzzey 7042a17698cSMartin Fuzzey if (!readval) 7052a17698cSMartin Fuzzey return mma8452_change_config(data, reg, writeval); 7062a17698cSMartin Fuzzey 7072a17698cSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, reg); 7082a17698cSMartin Fuzzey if (ret < 0) 7092a17698cSMartin Fuzzey return ret; 7102a17698cSMartin Fuzzey 7112a17698cSMartin Fuzzey *readval = ret; 7122a17698cSMartin Fuzzey 7132a17698cSMartin Fuzzey return 0; 7142a17698cSMartin Fuzzey } 7152a17698cSMartin Fuzzey 71628e34278SMartin Fuzzey static const struct iio_event_spec mma8452_transient_event[] = { 71728e34278SMartin Fuzzey { 718c5d0db06SMartin Kepplinger .type = IIO_EV_TYPE_MAG, 71928e34278SMartin Fuzzey .dir = IIO_EV_DIR_RISING, 72028e34278SMartin Fuzzey .mask_separate = BIT(IIO_EV_INFO_ENABLE), 7215dbbd19fSMartin Fuzzey .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 7221e79841aSMartin Fuzzey BIT(IIO_EV_INFO_PERIOD) | 7231e79841aSMartin Fuzzey BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB) 72428e34278SMartin Fuzzey }, 72528e34278SMartin Fuzzey }; 72628e34278SMartin Fuzzey 72728e34278SMartin Fuzzey /* 72828e34278SMartin Fuzzey * Threshold is configured in fixed 8G/127 steps regardless of 72928e34278SMartin Fuzzey * currently selected scale for measurement. 73028e34278SMartin Fuzzey */ 73128e34278SMartin Fuzzey static IIO_CONST_ATTR_NAMED(accel_transient_scale, in_accel_scale, "0.617742"); 73228e34278SMartin Fuzzey 73328e34278SMartin Fuzzey static struct attribute *mma8452_event_attributes[] = { 73428e34278SMartin Fuzzey &iio_const_attr_accel_transient_scale.dev_attr.attr, 73528e34278SMartin Fuzzey NULL, 73628e34278SMartin Fuzzey }; 73728e34278SMartin Fuzzey 73828e34278SMartin Fuzzey static struct attribute_group mma8452_event_attribute_group = { 73928e34278SMartin Fuzzey .attrs = mma8452_event_attributes, 74028e34278SMartin Fuzzey .name = "events", 74128e34278SMartin Fuzzey }; 74228e34278SMartin Fuzzey 743*c3cdd6e4SMartin Kepplinger #define MMA8452_CHANNEL(axis, idx, bits) { \ 744c7eeea93SPeter Meerwald .type = IIO_ACCEL, \ 745c7eeea93SPeter Meerwald .modified = 1, \ 746c7eeea93SPeter Meerwald .channel2 = IIO_MOD_##axis, \ 747c7eeea93SPeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 748c7eeea93SPeter Meerwald BIT(IIO_CHAN_INFO_CALIBBIAS), \ 749c7eeea93SPeter Meerwald .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 7501e79841aSMartin Fuzzey BIT(IIO_CHAN_INFO_SCALE) | \ 7511e79841aSMartin Fuzzey BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ 752c7eeea93SPeter Meerwald .scan_index = idx, \ 753c7eeea93SPeter Meerwald .scan_type = { \ 754c7eeea93SPeter Meerwald .sign = 's', \ 755*c3cdd6e4SMartin Kepplinger .realbits = (bits), \ 756c7eeea93SPeter Meerwald .storagebits = 16, \ 757*c3cdd6e4SMartin Kepplinger .shift = 16 - (bits), \ 758c7eeea93SPeter Meerwald .endianness = IIO_BE, \ 759c7eeea93SPeter Meerwald }, \ 76028e34278SMartin Fuzzey .event_spec = mma8452_transient_event, \ 76128e34278SMartin Fuzzey .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \ 762c7eeea93SPeter Meerwald } 763c7eeea93SPeter Meerwald 764c7eeea93SPeter Meerwald static const struct iio_chan_spec mma8452_channels[] = { 765*c3cdd6e4SMartin Kepplinger MMA8452_CHANNEL(X, 0, 12), 766*c3cdd6e4SMartin Kepplinger MMA8452_CHANNEL(Y, 1, 12), 767*c3cdd6e4SMartin Kepplinger MMA8452_CHANNEL(Z, 2, 12), 768c7eeea93SPeter Meerwald IIO_CHAN_SOFT_TIMESTAMP(3), 769c7eeea93SPeter Meerwald }; 770c7eeea93SPeter Meerwald 771*c3cdd6e4SMartin Kepplinger enum { 772*c3cdd6e4SMartin Kepplinger mma8452, 773*c3cdd6e4SMartin Kepplinger }; 774*c3cdd6e4SMartin Kepplinger 775*c3cdd6e4SMartin Kepplinger static const struct mma_chip_info mma_chip_info_table[] = { 776*c3cdd6e4SMartin Kepplinger [mma8452] = { 777*c3cdd6e4SMartin Kepplinger .chip_id = MMA8452_DEVICE_ID, 778*c3cdd6e4SMartin Kepplinger .channels = mma8452_channels, 779*c3cdd6e4SMartin Kepplinger .num_channels = ARRAY_SIZE(mma8452_channels), 780*c3cdd6e4SMartin Kepplinger /* 781*c3cdd6e4SMartin Kepplinger * Hardware has fullscale of -2G, -4G, -8G corresponding to 782*c3cdd6e4SMartin Kepplinger * raw value -2048 for 12 bit or -512 for 10 bit. 783*c3cdd6e4SMartin Kepplinger * The userspace interface uses m/s^2 and we declare micro units 784*c3cdd6e4SMartin Kepplinger * So scale factor for 12 bit here is given by: 785*c3cdd6e4SMartin Kepplinger * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 786*c3cdd6e4SMartin Kepplinger */ 787*c3cdd6e4SMartin Kepplinger .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, 788*c3cdd6e4SMartin Kepplinger .ev_cfg = MMA8452_TRANSIENT_CFG, 789*c3cdd6e4SMartin Kepplinger .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, 790*c3cdd6e4SMartin Kepplinger .ev_cfg_chan_shift = 1, 791*c3cdd6e4SMartin Kepplinger .ev_src = MMA8452_TRANSIENT_SRC, 792*c3cdd6e4SMartin Kepplinger .ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE, 793*c3cdd6e4SMartin Kepplinger .ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE, 794*c3cdd6e4SMartin Kepplinger .ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE, 795*c3cdd6e4SMartin Kepplinger .ev_ths = MMA8452_TRANSIENT_THS, 796*c3cdd6e4SMartin Kepplinger .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, 797*c3cdd6e4SMartin Kepplinger .ev_count = MMA8452_TRANSIENT_COUNT, 798*c3cdd6e4SMartin Kepplinger }, 799*c3cdd6e4SMartin Kepplinger }; 800*c3cdd6e4SMartin Kepplinger 801c7eeea93SPeter Meerwald static struct attribute *mma8452_attributes[] = { 802c7eeea93SPeter Meerwald &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 803c7eeea93SPeter Meerwald &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 8041e79841aSMartin Fuzzey &iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr, 805c7eeea93SPeter Meerwald NULL 806c7eeea93SPeter Meerwald }; 807c7eeea93SPeter Meerwald 808c7eeea93SPeter Meerwald static const struct attribute_group mma8452_group = { 809c7eeea93SPeter Meerwald .attrs = mma8452_attributes, 810c7eeea93SPeter Meerwald }; 811c7eeea93SPeter Meerwald 812c7eeea93SPeter Meerwald static const struct iio_info mma8452_info = { 813c7eeea93SPeter Meerwald .attrs = &mma8452_group, 814c7eeea93SPeter Meerwald .read_raw = &mma8452_read_raw, 815c7eeea93SPeter Meerwald .write_raw = &mma8452_write_raw, 81628e34278SMartin Fuzzey .event_attrs = &mma8452_event_attribute_group, 81728e34278SMartin Fuzzey .read_event_value = &mma8452_read_thresh, 81828e34278SMartin Fuzzey .write_event_value = &mma8452_write_thresh, 81928e34278SMartin Fuzzey .read_event_config = &mma8452_read_event_config, 82028e34278SMartin Fuzzey .write_event_config = &mma8452_write_event_config, 8212a17698cSMartin Fuzzey .debugfs_reg_access = &mma8452_reg_access_dbg, 822c7eeea93SPeter Meerwald .driver_module = THIS_MODULE, 823c7eeea93SPeter Meerwald }; 824c7eeea93SPeter Meerwald 825c7eeea93SPeter Meerwald static const unsigned long mma8452_scan_masks[] = {0x7, 0}; 826c7eeea93SPeter Meerwald 827ae6d9ce0SMartin Fuzzey static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig, 828ae6d9ce0SMartin Fuzzey bool state) 829ae6d9ce0SMartin Fuzzey { 830ae6d9ce0SMartin Fuzzey struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 831ae6d9ce0SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 832ae6d9ce0SMartin Fuzzey int reg; 833ae6d9ce0SMartin Fuzzey 834ae6d9ce0SMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4); 835ae6d9ce0SMartin Fuzzey if (reg < 0) 836ae6d9ce0SMartin Fuzzey return reg; 837ae6d9ce0SMartin Fuzzey 838ae6d9ce0SMartin Fuzzey if (state) 839ae6d9ce0SMartin Fuzzey reg |= MMA8452_INT_DRDY; 840ae6d9ce0SMartin Fuzzey else 841ae6d9ce0SMartin Fuzzey reg &= ~MMA8452_INT_DRDY; 842ae6d9ce0SMartin Fuzzey 843ae6d9ce0SMartin Fuzzey return mma8452_change_config(data, MMA8452_CTRL_REG4, reg); 844ae6d9ce0SMartin Fuzzey } 845ae6d9ce0SMartin Fuzzey 846ae6d9ce0SMartin Fuzzey static int mma8452_validate_device(struct iio_trigger *trig, 847ae6d9ce0SMartin Fuzzey struct iio_dev *indio_dev) 848ae6d9ce0SMartin Fuzzey { 849ae6d9ce0SMartin Fuzzey struct iio_dev *indio = iio_trigger_get_drvdata(trig); 850ae6d9ce0SMartin Fuzzey 851ae6d9ce0SMartin Fuzzey if (indio != indio_dev) 852ae6d9ce0SMartin Fuzzey return -EINVAL; 853ae6d9ce0SMartin Fuzzey 854ae6d9ce0SMartin Fuzzey return 0; 855ae6d9ce0SMartin Fuzzey } 856ae6d9ce0SMartin Fuzzey 857ae6d9ce0SMartin Fuzzey static const struct iio_trigger_ops mma8452_trigger_ops = { 858ae6d9ce0SMartin Fuzzey .set_trigger_state = mma8452_data_rdy_trigger_set_state, 859ae6d9ce0SMartin Fuzzey .validate_device = mma8452_validate_device, 860ae6d9ce0SMartin Fuzzey .owner = THIS_MODULE, 861ae6d9ce0SMartin Fuzzey }; 862ae6d9ce0SMartin Fuzzey 863ae6d9ce0SMartin Fuzzey static int mma8452_trigger_setup(struct iio_dev *indio_dev) 864ae6d9ce0SMartin Fuzzey { 865ae6d9ce0SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 866ae6d9ce0SMartin Fuzzey struct iio_trigger *trig; 867ae6d9ce0SMartin Fuzzey int ret; 868ae6d9ce0SMartin Fuzzey 869ae6d9ce0SMartin Fuzzey trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d", 870ae6d9ce0SMartin Fuzzey indio_dev->name, 871ae6d9ce0SMartin Fuzzey indio_dev->id); 872ae6d9ce0SMartin Fuzzey if (!trig) 873ae6d9ce0SMartin Fuzzey return -ENOMEM; 874ae6d9ce0SMartin Fuzzey 875ae6d9ce0SMartin Fuzzey trig->dev.parent = &data->client->dev; 876ae6d9ce0SMartin Fuzzey trig->ops = &mma8452_trigger_ops; 877ae6d9ce0SMartin Fuzzey iio_trigger_set_drvdata(trig, indio_dev); 878ae6d9ce0SMartin Fuzzey 879ae6d9ce0SMartin Fuzzey ret = iio_trigger_register(trig); 880ae6d9ce0SMartin Fuzzey if (ret) 881ae6d9ce0SMartin Fuzzey return ret; 882ae6d9ce0SMartin Fuzzey 883ae6d9ce0SMartin Fuzzey indio_dev->trig = trig; 884686027fbSHartmut Knaack 885ae6d9ce0SMartin Fuzzey return 0; 886ae6d9ce0SMartin Fuzzey } 887ae6d9ce0SMartin Fuzzey 888ae6d9ce0SMartin Fuzzey static void mma8452_trigger_cleanup(struct iio_dev *indio_dev) 889ae6d9ce0SMartin Fuzzey { 890ae6d9ce0SMartin Fuzzey if (indio_dev->trig) 891ae6d9ce0SMartin Fuzzey iio_trigger_unregister(indio_dev->trig); 892ae6d9ce0SMartin Fuzzey } 893ae6d9ce0SMartin Fuzzey 894ecabae71SMartin Fuzzey static int mma8452_reset(struct i2c_client *client) 895ecabae71SMartin Fuzzey { 896ecabae71SMartin Fuzzey int i; 897ecabae71SMartin Fuzzey int ret; 898ecabae71SMartin Fuzzey 899ecabae71SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2, 900ecabae71SMartin Fuzzey MMA8452_CTRL_REG2_RST); 901ecabae71SMartin Fuzzey if (ret < 0) 902ecabae71SMartin Fuzzey return ret; 903ecabae71SMartin Fuzzey 904ecabae71SMartin Fuzzey for (i = 0; i < 10; i++) { 905ecabae71SMartin Fuzzey usleep_range(100, 200); 906ecabae71SMartin Fuzzey ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2); 907ecabae71SMartin Fuzzey if (ret == -EIO) 908ecabae71SMartin Fuzzey continue; /* I2C comm reset */ 909ecabae71SMartin Fuzzey if (ret < 0) 910ecabae71SMartin Fuzzey return ret; 911ecabae71SMartin Fuzzey if (!(ret & MMA8452_CTRL_REG2_RST)) 912ecabae71SMartin Fuzzey return 0; 913ecabae71SMartin Fuzzey } 914ecabae71SMartin Fuzzey 915ecabae71SMartin Fuzzey return -ETIMEDOUT; 916ecabae71SMartin Fuzzey } 917ecabae71SMartin Fuzzey 918*c3cdd6e4SMartin Kepplinger static const struct of_device_id mma8452_dt_ids[] = { 919*c3cdd6e4SMartin Kepplinger { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] }, 920*c3cdd6e4SMartin Kepplinger { } 921*c3cdd6e4SMartin Kepplinger }; 922*c3cdd6e4SMartin Kepplinger MODULE_DEVICE_TABLE(of, mma8452_dt_ids); 923*c3cdd6e4SMartin Kepplinger 924c7eeea93SPeter Meerwald static int mma8452_probe(struct i2c_client *client, 925c7eeea93SPeter Meerwald const struct i2c_device_id *id) 926c7eeea93SPeter Meerwald { 927c7eeea93SPeter Meerwald struct mma8452_data *data; 928c7eeea93SPeter Meerwald struct iio_dev *indio_dev; 929c7eeea93SPeter Meerwald int ret; 930*c3cdd6e4SMartin Kepplinger const struct of_device_id *match; 931c7eeea93SPeter Meerwald 932c7eeea93SPeter Meerwald ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); 933c7eeea93SPeter Meerwald if (ret < 0) 934c7eeea93SPeter Meerwald return ret; 935c7eeea93SPeter Meerwald if (ret != MMA8452_DEVICE_ID) 936c7eeea93SPeter Meerwald return -ENODEV; 937c7eeea93SPeter Meerwald 938*c3cdd6e4SMartin Kepplinger match = of_match_device(mma8452_dt_ids, &client->dev); 939*c3cdd6e4SMartin Kepplinger if (!match) { 940*c3cdd6e4SMartin Kepplinger dev_err(&client->dev, "unknown device model\n"); 941*c3cdd6e4SMartin Kepplinger return -ENODEV; 942*c3cdd6e4SMartin Kepplinger } 943*c3cdd6e4SMartin Kepplinger 944c7eeea93SPeter Meerwald indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 945c7eeea93SPeter Meerwald if (!indio_dev) 946c7eeea93SPeter Meerwald return -ENOMEM; 947c7eeea93SPeter Meerwald 948c7eeea93SPeter Meerwald data = iio_priv(indio_dev); 949c7eeea93SPeter Meerwald data->client = client; 950c7eeea93SPeter Meerwald mutex_init(&data->lock); 951*c3cdd6e4SMartin Kepplinger data->chip_info = match->data; 952*c3cdd6e4SMartin Kepplinger 953*c3cdd6e4SMartin Kepplinger dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", 954*c3cdd6e4SMartin Kepplinger match->compatible, data->chip_info->chip_id); 955c7eeea93SPeter Meerwald 956c7eeea93SPeter Meerwald i2c_set_clientdata(client, indio_dev); 957c7eeea93SPeter Meerwald indio_dev->info = &mma8452_info; 958c7eeea93SPeter Meerwald indio_dev->name = id->name; 959c7eeea93SPeter Meerwald indio_dev->dev.parent = &client->dev; 960c7eeea93SPeter Meerwald indio_dev->modes = INDIO_DIRECT_MODE; 961*c3cdd6e4SMartin Kepplinger indio_dev->channels = data->chip_info->channels; 962*c3cdd6e4SMartin Kepplinger indio_dev->num_channels = data->chip_info->num_channels; 963c7eeea93SPeter Meerwald indio_dev->available_scan_masks = mma8452_scan_masks; 964c7eeea93SPeter Meerwald 965ecabae71SMartin Fuzzey ret = mma8452_reset(client); 966c7eeea93SPeter Meerwald if (ret < 0) 967c7eeea93SPeter Meerwald return ret; 968c7eeea93SPeter Meerwald 969c7eeea93SPeter Meerwald data->data_cfg = MMA8452_DATA_CFG_FS_2G; 970c7eeea93SPeter Meerwald ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, 971c7eeea93SPeter Meerwald data->data_cfg); 972c7eeea93SPeter Meerwald if (ret < 0) 973c7eeea93SPeter Meerwald return ret; 974c7eeea93SPeter Meerwald 97528e34278SMartin Fuzzey /* 97628e34278SMartin Fuzzey * By default set transient threshold to max to avoid events if 97728e34278SMartin Fuzzey * enabling without configuring threshold. 97828e34278SMartin Fuzzey */ 97928e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS, 98028e34278SMartin Fuzzey MMA8452_TRANSIENT_THS_MASK); 98128e34278SMartin Fuzzey if (ret < 0) 98228e34278SMartin Fuzzey return ret; 98328e34278SMartin Fuzzey 98428e34278SMartin Fuzzey if (client->irq) { 98528e34278SMartin Fuzzey /* 98628e34278SMartin Fuzzey * Although we enable the transient interrupt source once and 98728e34278SMartin Fuzzey * for all here the transient event detection itself is not 98828e34278SMartin Fuzzey * enabled until userspace asks for it by 98928e34278SMartin Fuzzey * mma8452_write_event_config() 99028e34278SMartin Fuzzey */ 991ae6d9ce0SMartin Fuzzey int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS; 992ae6d9ce0SMartin Fuzzey int enabled_interrupts = MMA8452_INT_TRANS; 99328e34278SMartin Fuzzey 99428e34278SMartin Fuzzey /* Assume wired to INT1 pin */ 99528e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, 99628e34278SMartin Fuzzey MMA8452_CTRL_REG5, 99728e34278SMartin Fuzzey supported_interrupts); 99828e34278SMartin Fuzzey if (ret < 0) 99928e34278SMartin Fuzzey return ret; 100028e34278SMartin Fuzzey 100128e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, 100228e34278SMartin Fuzzey MMA8452_CTRL_REG4, 1003ae6d9ce0SMartin Fuzzey enabled_interrupts); 1004ae6d9ce0SMartin Fuzzey if (ret < 0) 1005ae6d9ce0SMartin Fuzzey return ret; 1006ae6d9ce0SMartin Fuzzey 1007ae6d9ce0SMartin Fuzzey ret = mma8452_trigger_setup(indio_dev); 100828e34278SMartin Fuzzey if (ret < 0) 100928e34278SMartin Fuzzey return ret; 101028e34278SMartin Fuzzey } 101128e34278SMartin Fuzzey 1012ecabae71SMartin Fuzzey data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | 1013ecabae71SMartin Fuzzey (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); 1014ecabae71SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1, 1015ecabae71SMartin Fuzzey data->ctrl_reg1); 1016ecabae71SMartin Fuzzey if (ret < 0) 1017ae6d9ce0SMartin Fuzzey goto trigger_cleanup; 1018ecabae71SMartin Fuzzey 1019c7eeea93SPeter Meerwald ret = iio_triggered_buffer_setup(indio_dev, NULL, 1020c7eeea93SPeter Meerwald mma8452_trigger_handler, NULL); 1021c7eeea93SPeter Meerwald if (ret < 0) 1022ae6d9ce0SMartin Fuzzey goto trigger_cleanup; 1023c7eeea93SPeter Meerwald 102428e34278SMartin Fuzzey if (client->irq) { 102528e34278SMartin Fuzzey ret = devm_request_threaded_irq(&client->dev, 102628e34278SMartin Fuzzey client->irq, 102728e34278SMartin Fuzzey NULL, mma8452_interrupt, 102828e34278SMartin Fuzzey IRQF_TRIGGER_LOW | IRQF_ONESHOT, 102928e34278SMartin Fuzzey client->name, indio_dev); 103028e34278SMartin Fuzzey if (ret) 103128e34278SMartin Fuzzey goto buffer_cleanup; 103228e34278SMartin Fuzzey } 103328e34278SMartin Fuzzey 1034c7eeea93SPeter Meerwald ret = iio_device_register(indio_dev); 1035c7eeea93SPeter Meerwald if (ret < 0) 1036c7eeea93SPeter Meerwald goto buffer_cleanup; 103728e34278SMartin Fuzzey 1038c7eeea93SPeter Meerwald return 0; 1039c7eeea93SPeter Meerwald 1040c7eeea93SPeter Meerwald buffer_cleanup: 1041c7eeea93SPeter Meerwald iio_triggered_buffer_cleanup(indio_dev); 1042ae6d9ce0SMartin Fuzzey 1043ae6d9ce0SMartin Fuzzey trigger_cleanup: 1044ae6d9ce0SMartin Fuzzey mma8452_trigger_cleanup(indio_dev); 1045ae6d9ce0SMartin Fuzzey 1046c7eeea93SPeter Meerwald return ret; 1047c7eeea93SPeter Meerwald } 1048c7eeea93SPeter Meerwald 1049c7eeea93SPeter Meerwald static int mma8452_remove(struct i2c_client *client) 1050c7eeea93SPeter Meerwald { 1051c7eeea93SPeter Meerwald struct iio_dev *indio_dev = i2c_get_clientdata(client); 1052c7eeea93SPeter Meerwald 1053c7eeea93SPeter Meerwald iio_device_unregister(indio_dev); 1054c7eeea93SPeter Meerwald iio_triggered_buffer_cleanup(indio_dev); 1055ae6d9ce0SMartin Fuzzey mma8452_trigger_cleanup(indio_dev); 1056c7eeea93SPeter Meerwald mma8452_standby(iio_priv(indio_dev)); 1057c7eeea93SPeter Meerwald 1058c7eeea93SPeter Meerwald return 0; 1059c7eeea93SPeter Meerwald } 1060c7eeea93SPeter Meerwald 1061c7eeea93SPeter Meerwald #ifdef CONFIG_PM_SLEEP 1062c7eeea93SPeter Meerwald static int mma8452_suspend(struct device *dev) 1063c7eeea93SPeter Meerwald { 1064c7eeea93SPeter Meerwald return mma8452_standby(iio_priv(i2c_get_clientdata( 1065c7eeea93SPeter Meerwald to_i2c_client(dev)))); 1066c7eeea93SPeter Meerwald } 1067c7eeea93SPeter Meerwald 1068c7eeea93SPeter Meerwald static int mma8452_resume(struct device *dev) 1069c7eeea93SPeter Meerwald { 1070c7eeea93SPeter Meerwald return mma8452_active(iio_priv(i2c_get_clientdata( 1071c7eeea93SPeter Meerwald to_i2c_client(dev)))); 1072c7eeea93SPeter Meerwald } 1073c7eeea93SPeter Meerwald 1074c7eeea93SPeter Meerwald static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume); 1075c7eeea93SPeter Meerwald #define MMA8452_PM_OPS (&mma8452_pm_ops) 1076c7eeea93SPeter Meerwald #else 1077c7eeea93SPeter Meerwald #define MMA8452_PM_OPS NULL 1078c7eeea93SPeter Meerwald #endif 1079c7eeea93SPeter Meerwald 1080c7eeea93SPeter Meerwald static const struct i2c_device_id mma8452_id[] = { 1081*c3cdd6e4SMartin Kepplinger { "mma8452", mma8452 }, 1082c7eeea93SPeter Meerwald { } 1083c7eeea93SPeter Meerwald }; 1084c7eeea93SPeter Meerwald MODULE_DEVICE_TABLE(i2c, mma8452_id); 1085c7eeea93SPeter Meerwald 1086c7eeea93SPeter Meerwald static struct i2c_driver mma8452_driver = { 1087c7eeea93SPeter Meerwald .driver = { 1088c7eeea93SPeter Meerwald .name = "mma8452", 1089a3fb96a8SMartin Fuzzey .of_match_table = of_match_ptr(mma8452_dt_ids), 1090c7eeea93SPeter Meerwald .pm = MMA8452_PM_OPS, 1091c7eeea93SPeter Meerwald }, 1092c7eeea93SPeter Meerwald .probe = mma8452_probe, 1093c7eeea93SPeter Meerwald .remove = mma8452_remove, 1094c7eeea93SPeter Meerwald .id_table = mma8452_id, 1095c7eeea93SPeter Meerwald }; 1096c7eeea93SPeter Meerwald module_i2c_driver(mma8452_driver); 1097c7eeea93SPeter Meerwald 1098c7eeea93SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 1099c7eeea93SPeter Meerwald MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver"); 1100c7eeea93SPeter Meerwald MODULE_LICENSE("GPL"); 1101