1c7eeea93SPeter Meerwald /* 2f26ab1aaSMartin Kepplinger * mma8452.c - Support for following Freescale / NXP 3-axis accelerometers: 3c5ea1b58SMartin Kepplinger * 416df666aSMartin Kepplinger * device name digital output 7-bit I2C slave address (pin selectable) 516df666aSMartin Kepplinger * --------------------------------------------------------------------- 616df666aSMartin Kepplinger * MMA8451Q 14 bit 0x1c / 0x1d 716df666aSMartin Kepplinger * MMA8452Q 12 bit 0x1c / 0x1d 816df666aSMartin Kepplinger * MMA8453Q 10 bit 0x1c / 0x1d 916df666aSMartin Kepplinger * MMA8652FC 12 bit 0x1d 1016df666aSMartin Kepplinger * MMA8653FC 10 bit 0x1d 1116df666aSMartin Kepplinger * FXLS8471Q 14 bit 0x1e / 0x1d / 0x1c / 0x1f 12c7eeea93SPeter Meerwald * 1340836bc3SMartin Kepplinger * Copyright 2015 Martin Kepplinger <martink@posteo.de> 14c7eeea93SPeter Meerwald * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net> 15c7eeea93SPeter Meerwald * 16c7eeea93SPeter Meerwald * This file is subject to the terms and conditions of version 2 of 17c7eeea93SPeter Meerwald * the GNU General Public License. See the file COPYING in the main 18c7eeea93SPeter Meerwald * directory of this archive for more details. 19c7eeea93SPeter Meerwald * 20bce59b60SMartin Kepplinger * TODO: orientation events 21c7eeea93SPeter Meerwald */ 22c7eeea93SPeter Meerwald 23c7eeea93SPeter Meerwald #include <linux/module.h> 24c7eeea93SPeter Meerwald #include <linux/i2c.h> 25c7eeea93SPeter Meerwald #include <linux/iio/iio.h> 26c7eeea93SPeter Meerwald #include <linux/iio/sysfs.h> 27c7eeea93SPeter Meerwald #include <linux/iio/buffer.h> 28ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger.h> 29ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger_consumer.h> 30c7eeea93SPeter Meerwald #include <linux/iio/triggered_buffer.h> 3128e34278SMartin Fuzzey #include <linux/iio/events.h> 32c7eeea93SPeter Meerwald #include <linux/delay.h> 33c3cdd6e4SMartin Kepplinger #include <linux/of_device.h> 34d2a3e093SMartin Kepplinger #include <linux/of_irq.h> 3596c0cb2bSMartin Kepplinger #include <linux/pm_runtime.h> 36c7eeea93SPeter Meerwald 37c7eeea93SPeter Meerwald #define MMA8452_STATUS 0x00 3869abff81SHartmut Knaack #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) 39c5ea1b58SMartin Kepplinger #define MMA8452_OUT_X 0x01 /* MSB first */ 40c7eeea93SPeter Meerwald #define MMA8452_OUT_Y 0x03 41c7eeea93SPeter Meerwald #define MMA8452_OUT_Z 0x05 4228e34278SMartin Fuzzey #define MMA8452_INT_SRC 0x0c 43c7eeea93SPeter Meerwald #define MMA8452_WHO_AM_I 0x0d 44c7eeea93SPeter Meerwald #define MMA8452_DATA_CFG 0x0e 4569abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0) 4669abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_2G 0 4769abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_4G 1 4869abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_8G 2 4969abff81SHartmut Knaack #define MMA8452_DATA_CFG_HPF_MASK BIT(4) 501e79841aSMartin Fuzzey #define MMA8452_HP_FILTER_CUTOFF 0x0f 5169abff81SHartmut Knaack #define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0) 5260f562e7SMartin Kepplinger #define MMA8452_FF_MT_CFG 0x15 5360f562e7SMartin Kepplinger #define MMA8452_FF_MT_CFG_OAE BIT(6) 5460f562e7SMartin Kepplinger #define MMA8452_FF_MT_CFG_ELE BIT(7) 5560f562e7SMartin Kepplinger #define MMA8452_FF_MT_SRC 0x16 5660f562e7SMartin Kepplinger #define MMA8452_FF_MT_SRC_XHE BIT(1) 5760f562e7SMartin Kepplinger #define MMA8452_FF_MT_SRC_YHE BIT(3) 5860f562e7SMartin Kepplinger #define MMA8452_FF_MT_SRC_ZHE BIT(5) 5960f562e7SMartin Kepplinger #define MMA8452_FF_MT_THS 0x17 6060f562e7SMartin Kepplinger #define MMA8452_FF_MT_THS_MASK 0x7f 6160f562e7SMartin Kepplinger #define MMA8452_FF_MT_COUNT 0x18 62605f72deSHarinath Nampally #define MMA8452_FF_MT_CHAN_SHIFT 3 6328e34278SMartin Fuzzey #define MMA8452_TRANSIENT_CFG 0x1d 64605f72deSHarinath Nampally #define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) 651e79841aSMartin Fuzzey #define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) 6669abff81SHartmut Knaack #define MMA8452_TRANSIENT_CFG_ELE BIT(4) 6728e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC 0x1e 6828e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) 6928e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) 7028e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) 7128e34278SMartin Fuzzey #define MMA8452_TRANSIENT_THS 0x1f 7269abff81SHartmut Knaack #define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0) 735dbbd19fSMartin Fuzzey #define MMA8452_TRANSIENT_COUNT 0x20 74605f72deSHarinath Nampally #define MMA8452_TRANSIENT_CHAN_SHIFT 1 75c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG1 0x2a 7669abff81SHartmut Knaack #define MMA8452_CTRL_ACTIVE BIT(0) 7769abff81SHartmut Knaack #define MMA8452_CTRL_DR_MASK GENMASK(5, 3) 7869abff81SHartmut Knaack #define MMA8452_CTRL_DR_SHIFT 3 7969abff81SHartmut Knaack #define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ 80c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG2 0x2b 81ecabae71SMartin Fuzzey #define MMA8452_CTRL_REG2_RST BIT(6) 82ed859fc1SMartin Kepplinger #define MMA8452_CTRL_REG2_MODS_SHIFT 3 83ed859fc1SMartin Kepplinger #define MMA8452_CTRL_REG2_MODS_MASK 0x1b 8428e34278SMartin Fuzzey #define MMA8452_CTRL_REG4 0x2d 8528e34278SMartin Fuzzey #define MMA8452_CTRL_REG5 0x2e 8669abff81SHartmut Knaack #define MMA8452_OFF_X 0x2f 8769abff81SHartmut Knaack #define MMA8452_OFF_Y 0x30 8869abff81SHartmut Knaack #define MMA8452_OFF_Z 0x31 89c7eeea93SPeter Meerwald 902a17698cSMartin Fuzzey #define MMA8452_MAX_REG 0x31 912a17698cSMartin Fuzzey 92ae6d9ce0SMartin Fuzzey #define MMA8452_INT_DRDY BIT(0) 9360f562e7SMartin Kepplinger #define MMA8452_INT_FF_MT BIT(2) 9428e34278SMartin Fuzzey #define MMA8452_INT_TRANS BIT(5) 9528e34278SMartin Fuzzey 96244a93f6SMartin Kepplinger #define MMA8451_DEVICE_ID 0x1a 97c7eeea93SPeter Meerwald #define MMA8452_DEVICE_ID 0x2a 98c5ea1b58SMartin Kepplinger #define MMA8453_DEVICE_ID 0x3a 99417e008bSMartin Kepplinger #define MMA8652_DEVICE_ID 0x4a 100417e008bSMartin Kepplinger #define MMA8653_DEVICE_ID 0x5a 101e8731180SMartin Kepplinger #define FXLS8471_DEVICE_ID 0x6a 102c7eeea93SPeter Meerwald 10396c0cb2bSMartin Kepplinger #define MMA8452_AUTO_SUSPEND_DELAY_MS 2000 10496c0cb2bSMartin Kepplinger 105c7eeea93SPeter Meerwald struct mma8452_data { 106c7eeea93SPeter Meerwald struct i2c_client *client; 107c7eeea93SPeter Meerwald struct mutex lock; 108c7eeea93SPeter Meerwald u8 ctrl_reg1; 109c7eeea93SPeter Meerwald u8 data_cfg; 110c3cdd6e4SMartin Kepplinger const struct mma_chip_info *chip_info; 111c3cdd6e4SMartin Kepplinger }; 112c3cdd6e4SMartin Kepplinger 113c3cdd6e4SMartin Kepplinger /** 114605f72deSHarinath Nampally * struct mma8452_event_regs - chip specific data related to events 115c3cdd6e4SMartin Kepplinger * @ev_cfg: event config register address 116c3cdd6e4SMartin Kepplinger * @ev_cfg_ele: latch bit in event config register 117c3cdd6e4SMartin Kepplinger * @ev_cfg_chan_shift: number of the bit to enable events in X 118c3cdd6e4SMartin Kepplinger * direction; in event config register 119c3cdd6e4SMartin Kepplinger * @ev_src: event source register address 120c3cdd6e4SMartin Kepplinger * @ev_ths: event threshold register address 121c3cdd6e4SMartin Kepplinger * @ev_ths_mask: mask for the threshold value 122c3cdd6e4SMartin Kepplinger * @ev_count: event count (period) register address 123c3cdd6e4SMartin Kepplinger * 124c3cdd6e4SMartin Kepplinger * Since not all chips supported by the driver support comparing high pass 125c3cdd6e4SMartin Kepplinger * filtered data for events (interrupts), different interrupt sources are 126c3cdd6e4SMartin Kepplinger * used for different chips and the relevant registers are included here. 127c3cdd6e4SMartin Kepplinger */ 128605f72deSHarinath Nampally struct mma8452_event_regs { 129605f72deSHarinath Nampally u8 ev_cfg; 130605f72deSHarinath Nampally u8 ev_cfg_ele; 131605f72deSHarinath Nampally u8 ev_cfg_chan_shift; 132605f72deSHarinath Nampally u8 ev_src; 133605f72deSHarinath Nampally u8 ev_ths; 134605f72deSHarinath Nampally u8 ev_ths_mask; 135605f72deSHarinath Nampally u8 ev_count; 136605f72deSHarinath Nampally }; 137605f72deSHarinath Nampally 138605f72deSHarinath Nampally static const struct mma8452_event_regs ev_regs_accel_falling = { 139605f72deSHarinath Nampally .ev_cfg = MMA8452_FF_MT_CFG, 140605f72deSHarinath Nampally .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, 141605f72deSHarinath Nampally .ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT, 142605f72deSHarinath Nampally .ev_src = MMA8452_FF_MT_SRC, 143605f72deSHarinath Nampally .ev_ths = MMA8452_FF_MT_THS, 144605f72deSHarinath Nampally .ev_ths_mask = MMA8452_FF_MT_THS_MASK, 145605f72deSHarinath Nampally .ev_count = MMA8452_FF_MT_COUNT 146605f72deSHarinath Nampally }; 147605f72deSHarinath Nampally 148605f72deSHarinath Nampally static const struct mma8452_event_regs ev_regs_accel_rising = { 149605f72deSHarinath Nampally .ev_cfg = MMA8452_TRANSIENT_CFG, 150605f72deSHarinath Nampally .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, 151605f72deSHarinath Nampally .ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT, 152605f72deSHarinath Nampally .ev_src = MMA8452_TRANSIENT_SRC, 153605f72deSHarinath Nampally .ev_ths = MMA8452_TRANSIENT_THS, 154605f72deSHarinath Nampally .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, 155605f72deSHarinath Nampally .ev_count = MMA8452_TRANSIENT_COUNT, 156605f72deSHarinath Nampally }; 157605f72deSHarinath Nampally 158605f72deSHarinath Nampally /** 159605f72deSHarinath Nampally * struct mma_chip_info - chip specific data 160605f72deSHarinath Nampally * @chip_id: WHO_AM_I register's value 161605f72deSHarinath Nampally * @channels: struct iio_chan_spec matching the device's 162605f72deSHarinath Nampally * capabilities 163605f72deSHarinath Nampally * @num_channels: number of channels 164605f72deSHarinath Nampally * @mma_scales: scale factors for converting register values 165605f72deSHarinath Nampally * to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers 166605f72deSHarinath Nampally * per mode: m/s^2 and micro m/s^2 167605f72deSHarinath Nampally * @all_events: all events supported by this chip 168605f72deSHarinath Nampally * @enabled_events: event flags enabled and handled by this driver 169605f72deSHarinath Nampally */ 170c3cdd6e4SMartin Kepplinger struct mma_chip_info { 171c3cdd6e4SMartin Kepplinger u8 chip_id; 172c3cdd6e4SMartin Kepplinger const struct iio_chan_spec *channels; 173c3cdd6e4SMartin Kepplinger int num_channels; 174c3cdd6e4SMartin Kepplinger const int mma_scales[3][2]; 175605f72deSHarinath Nampally int all_events; 176605f72deSHarinath Nampally int enabled_events; 177c7eeea93SPeter Meerwald }; 178c7eeea93SPeter Meerwald 179e60378c1SMartin Kepplinger enum { 180e60378c1SMartin Kepplinger idx_x, 181e60378c1SMartin Kepplinger idx_y, 182e60378c1SMartin Kepplinger idx_z, 183e60378c1SMartin Kepplinger idx_ts, 184e60378c1SMartin Kepplinger }; 185e60378c1SMartin Kepplinger 186c7eeea93SPeter Meerwald static int mma8452_drdy(struct mma8452_data *data) 187c7eeea93SPeter Meerwald { 188c7eeea93SPeter Meerwald int tries = 150; 189c7eeea93SPeter Meerwald 190c7eeea93SPeter Meerwald while (tries-- > 0) { 191c7eeea93SPeter Meerwald int ret = i2c_smbus_read_byte_data(data->client, 192c7eeea93SPeter Meerwald MMA8452_STATUS); 193c7eeea93SPeter Meerwald if (ret < 0) 194c7eeea93SPeter Meerwald return ret; 195c7eeea93SPeter Meerwald if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) 196c7eeea93SPeter Meerwald return 0; 197686027fbSHartmut Knaack 198c7eeea93SPeter Meerwald msleep(20); 199c7eeea93SPeter Meerwald } 200c7eeea93SPeter Meerwald 201c7eeea93SPeter Meerwald dev_err(&data->client->dev, "data not ready\n"); 202686027fbSHartmut Knaack 203c7eeea93SPeter Meerwald return -EIO; 204c7eeea93SPeter Meerwald } 205c7eeea93SPeter Meerwald 20696c0cb2bSMartin Kepplinger static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on) 20796c0cb2bSMartin Kepplinger { 20896c0cb2bSMartin Kepplinger #ifdef CONFIG_PM 20996c0cb2bSMartin Kepplinger int ret; 21096c0cb2bSMartin Kepplinger 21196c0cb2bSMartin Kepplinger if (on) { 21296c0cb2bSMartin Kepplinger ret = pm_runtime_get_sync(&client->dev); 21396c0cb2bSMartin Kepplinger } else { 21496c0cb2bSMartin Kepplinger pm_runtime_mark_last_busy(&client->dev); 21596c0cb2bSMartin Kepplinger ret = pm_runtime_put_autosuspend(&client->dev); 21696c0cb2bSMartin Kepplinger } 21796c0cb2bSMartin Kepplinger 21896c0cb2bSMartin Kepplinger if (ret < 0) { 21996c0cb2bSMartin Kepplinger dev_err(&client->dev, 22096c0cb2bSMartin Kepplinger "failed to change power state to %d\n", on); 22196c0cb2bSMartin Kepplinger if (on) 22296c0cb2bSMartin Kepplinger pm_runtime_put_noidle(&client->dev); 22396c0cb2bSMartin Kepplinger 22496c0cb2bSMartin Kepplinger return ret; 22596c0cb2bSMartin Kepplinger } 22696c0cb2bSMartin Kepplinger #endif 22796c0cb2bSMartin Kepplinger 22896c0cb2bSMartin Kepplinger return 0; 22996c0cb2bSMartin Kepplinger } 23096c0cb2bSMartin Kepplinger 231c7eeea93SPeter Meerwald static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) 232c7eeea93SPeter Meerwald { 233c7eeea93SPeter Meerwald int ret = mma8452_drdy(data); 234686027fbSHartmut Knaack 235c7eeea93SPeter Meerwald if (ret < 0) 236c7eeea93SPeter Meerwald return ret; 237686027fbSHartmut Knaack 23896c0cb2bSMartin Kepplinger ret = mma8452_set_runtime_pm_state(data->client, true); 23996c0cb2bSMartin Kepplinger if (ret) 24096c0cb2bSMartin Kepplinger return ret; 24196c0cb2bSMartin Kepplinger 24296c0cb2bSMartin Kepplinger ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X, 243686027fbSHartmut Knaack 3 * sizeof(__be16), (u8 *)buf); 24496c0cb2bSMartin Kepplinger 24596c0cb2bSMartin Kepplinger ret = mma8452_set_runtime_pm_state(data->client, false); 24696c0cb2bSMartin Kepplinger 24796c0cb2bSMartin Kepplinger return ret; 248c7eeea93SPeter Meerwald } 249c7eeea93SPeter Meerwald 250686027fbSHartmut Knaack static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2], 251686027fbSHartmut Knaack int n) 252c7eeea93SPeter Meerwald { 253c7eeea93SPeter Meerwald size_t len = 0; 254c7eeea93SPeter Meerwald 255c7eeea93SPeter Meerwald while (n-- > 0) 256686027fbSHartmut Knaack len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", 257686027fbSHartmut Knaack vals[n][0], vals[n][1]); 258c7eeea93SPeter Meerwald 259c7eeea93SPeter Meerwald /* replace trailing space by newline */ 260c7eeea93SPeter Meerwald buf[len - 1] = '\n'; 261c7eeea93SPeter Meerwald 262c7eeea93SPeter Meerwald return len; 263c7eeea93SPeter Meerwald } 264c7eeea93SPeter Meerwald 265c7eeea93SPeter Meerwald static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n, 266c7eeea93SPeter Meerwald int val, int val2) 267c7eeea93SPeter Meerwald { 268c7eeea93SPeter Meerwald while (n-- > 0) 269c7eeea93SPeter Meerwald if (val == vals[n][0] && val2 == vals[n][1]) 270c7eeea93SPeter Meerwald return n; 271c7eeea93SPeter Meerwald 272c7eeea93SPeter Meerwald return -EINVAL; 273c7eeea93SPeter Meerwald } 274c7eeea93SPeter Meerwald 27532b28076SMartin Kepplinger static unsigned int mma8452_get_odr_index(struct mma8452_data *data) 2765dbbd19fSMartin Fuzzey { 2775dbbd19fSMartin Fuzzey return (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >> 2785dbbd19fSMartin Fuzzey MMA8452_CTRL_DR_SHIFT; 2795dbbd19fSMartin Fuzzey } 2805dbbd19fSMartin Fuzzey 281c7eeea93SPeter Meerwald static const int mma8452_samp_freq[8][2] = { 282c7eeea93SPeter Meerwald {800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000}, 283c7eeea93SPeter Meerwald {6, 250000}, {1, 560000} 284c7eeea93SPeter Meerwald }; 285c7eeea93SPeter Meerwald 286ed859fc1SMartin Kepplinger /* Datasheet table: step time "Relationship with the ODR" (sample frequency) */ 28732b28076SMartin Kepplinger static const unsigned int mma8452_transient_time_step_us[4][8] = { 288ed859fc1SMartin Kepplinger { 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 }, /* normal */ 289ed859fc1SMartin Kepplinger { 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 }, /* l p l n */ 290ed859fc1SMartin Kepplinger { 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 }, /* high res*/ 291ed859fc1SMartin Kepplinger { 1250, 2500, 5000, 10000, 20000, 80000, 160000, 160000 } /* l p */ 2925dbbd19fSMartin Fuzzey }; 2935dbbd19fSMartin Fuzzey 294ed859fc1SMartin Kepplinger /* Datasheet table "High-Pass Filter Cutoff Options" */ 295ed859fc1SMartin Kepplinger static const int mma8452_hp_filter_cutoff[4][8][4][2] = { 296ed859fc1SMartin Kepplinger { /* normal */ 2971e79841aSMartin Fuzzey { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 800 Hz sample */ 2981e79841aSMartin Fuzzey { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 400 Hz sample */ 2991e79841aSMartin Fuzzey { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, /* 200 Hz sample */ 3001e79841aSMartin Fuzzey { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, /* 100 Hz sample */ 3011e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 50 Hz sample */ 3021e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 12.5 Hz sample */ 3031e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 6.25 Hz sample */ 3041e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} } /* 1.56 Hz sample */ 305ed859fc1SMartin Kepplinger }, 306ed859fc1SMartin Kepplinger { /* low noise low power */ 307ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 308ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 309ed859fc1SMartin Kepplinger { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, 310ed859fc1SMartin Kepplinger { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, 311ed859fc1SMartin Kepplinger { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, 312ed859fc1SMartin Kepplinger { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }, 313ed859fc1SMartin Kepplinger { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }, 314ed859fc1SMartin Kepplinger { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} } 315ed859fc1SMartin Kepplinger }, 316ed859fc1SMartin Kepplinger { /* high resolution */ 317ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 318ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 319ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 320ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 321ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 322ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 323ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 324ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} } 325ed859fc1SMartin Kepplinger }, 326ed859fc1SMartin Kepplinger { /* low power */ 327ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 328ed859fc1SMartin Kepplinger { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, 329ed859fc1SMartin Kepplinger { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, 330ed859fc1SMartin Kepplinger { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, 331ed859fc1SMartin Kepplinger { {1, 0}, {0, 500000}, {0, 250000}, {0, 125000} }, 332ed859fc1SMartin Kepplinger { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }, 333ed859fc1SMartin Kepplinger { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }, 334ed859fc1SMartin Kepplinger { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} } 335ed859fc1SMartin Kepplinger } 3361e79841aSMartin Fuzzey }; 3371e79841aSMartin Fuzzey 338ed859fc1SMartin Kepplinger /* Datasheet table "MODS Oversampling modes averaging values at each ODR" */ 339ed859fc1SMartin Kepplinger static const u16 mma8452_os_ratio[4][8] = { 340ed859fc1SMartin Kepplinger /* 800 Hz, 400 Hz, ... , 1.56 Hz */ 341ed859fc1SMartin Kepplinger { 2, 4, 4, 4, 4, 16, 32, 128 }, /* normal */ 342ed859fc1SMartin Kepplinger { 2, 4, 4, 4, 4, 4, 8, 32 }, /* low power low noise */ 343ed859fc1SMartin Kepplinger { 2, 4, 8, 16, 32, 128, 256, 1024 }, /* high resolution */ 344ed859fc1SMartin Kepplinger { 2, 2, 2, 2, 2, 2, 4, 16 } /* low power */ 345ed859fc1SMartin Kepplinger }; 346ed859fc1SMartin Kepplinger 347ed859fc1SMartin Kepplinger static int mma8452_get_power_mode(struct mma8452_data *data) 348ed859fc1SMartin Kepplinger { 349ed859fc1SMartin Kepplinger int reg; 350ed859fc1SMartin Kepplinger 351ed859fc1SMartin Kepplinger reg = i2c_smbus_read_byte_data(data->client, 352ed859fc1SMartin Kepplinger MMA8452_CTRL_REG2); 353ed859fc1SMartin Kepplinger if (reg < 0) 354ed859fc1SMartin Kepplinger return reg; 355ed859fc1SMartin Kepplinger 356ed859fc1SMartin Kepplinger return ((reg & MMA8452_CTRL_REG2_MODS_MASK) >> 357ed859fc1SMartin Kepplinger MMA8452_CTRL_REG2_MODS_SHIFT); 358ed859fc1SMartin Kepplinger } 359ed859fc1SMartin Kepplinger 360c7eeea93SPeter Meerwald static ssize_t mma8452_show_samp_freq_avail(struct device *dev, 361686027fbSHartmut Knaack struct device_attribute *attr, 362686027fbSHartmut Knaack char *buf) 363c7eeea93SPeter Meerwald { 364c7eeea93SPeter Meerwald return mma8452_show_int_plus_micros(buf, mma8452_samp_freq, 365c7eeea93SPeter Meerwald ARRAY_SIZE(mma8452_samp_freq)); 366c7eeea93SPeter Meerwald } 367c7eeea93SPeter Meerwald 368c7eeea93SPeter Meerwald static ssize_t mma8452_show_scale_avail(struct device *dev, 369686027fbSHartmut Knaack struct device_attribute *attr, 370686027fbSHartmut Knaack char *buf) 371c7eeea93SPeter Meerwald { 372c3cdd6e4SMartin Kepplinger struct mma8452_data *data = iio_priv(i2c_get_clientdata( 373c3cdd6e4SMartin Kepplinger to_i2c_client(dev))); 374c3cdd6e4SMartin Kepplinger 375c3cdd6e4SMartin Kepplinger return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales, 376c3cdd6e4SMartin Kepplinger ARRAY_SIZE(data->chip_info->mma_scales)); 377c7eeea93SPeter Meerwald } 378c7eeea93SPeter Meerwald 3791e79841aSMartin Fuzzey static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, 3801e79841aSMartin Fuzzey struct device_attribute *attr, 3811e79841aSMartin Fuzzey char *buf) 3821e79841aSMartin Fuzzey { 3831e79841aSMartin Fuzzey struct iio_dev *indio_dev = dev_to_iio_dev(dev); 3841e79841aSMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 385ed859fc1SMartin Kepplinger int i, j; 3861e79841aSMartin Fuzzey 387ed859fc1SMartin Kepplinger i = mma8452_get_odr_index(data); 388ed859fc1SMartin Kepplinger j = mma8452_get_power_mode(data); 389ed859fc1SMartin Kepplinger if (j < 0) 390ed859fc1SMartin Kepplinger return j; 391ed859fc1SMartin Kepplinger 392ed859fc1SMartin Kepplinger return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[j][i], 393ed859fc1SMartin Kepplinger ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0])); 394ed859fc1SMartin Kepplinger } 395ed859fc1SMartin Kepplinger 396ed859fc1SMartin Kepplinger static ssize_t mma8452_show_os_ratio_avail(struct device *dev, 397ed859fc1SMartin Kepplinger struct device_attribute *attr, 398ed859fc1SMartin Kepplinger char *buf) 399ed859fc1SMartin Kepplinger { 400ed859fc1SMartin Kepplinger struct iio_dev *indio_dev = dev_to_iio_dev(dev); 401ed859fc1SMartin Kepplinger struct mma8452_data *data = iio_priv(indio_dev); 402ed859fc1SMartin Kepplinger int i = mma8452_get_odr_index(data); 403ed859fc1SMartin Kepplinger int j; 404ed859fc1SMartin Kepplinger u16 val = 0; 405ed859fc1SMartin Kepplinger size_t len = 0; 406ed859fc1SMartin Kepplinger 407ed859fc1SMartin Kepplinger for (j = 0; j < ARRAY_SIZE(mma8452_os_ratio); j++) { 408ed859fc1SMartin Kepplinger if (val == mma8452_os_ratio[j][i]) 409ed859fc1SMartin Kepplinger continue; 410ed859fc1SMartin Kepplinger 411ed859fc1SMartin Kepplinger val = mma8452_os_ratio[j][i]; 412ed859fc1SMartin Kepplinger 413ed859fc1SMartin Kepplinger len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val); 414ed859fc1SMartin Kepplinger } 415ed859fc1SMartin Kepplinger buf[len - 1] = '\n'; 416ed859fc1SMartin Kepplinger 417ed859fc1SMartin Kepplinger return len; 4181e79841aSMartin Fuzzey } 4191e79841aSMartin Fuzzey 420c7eeea93SPeter Meerwald static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); 421*cd327b00SHarinath Nampally static IIO_DEVICE_ATTR(in_accel_scale_available, 0444, 422c7eeea93SPeter Meerwald mma8452_show_scale_avail, NULL, 0); 4231e79841aSMartin Fuzzey static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available, 424*cd327b00SHarinath Nampally 0444, mma8452_show_hp_cutoff_avail, NULL, 0); 425*cd327b00SHarinath Nampally static IIO_DEVICE_ATTR(in_accel_oversampling_ratio_available, 0444, 426ed859fc1SMartin Kepplinger mma8452_show_os_ratio_avail, NULL, 0); 427c7eeea93SPeter Meerwald 428c7eeea93SPeter Meerwald static int mma8452_get_samp_freq_index(struct mma8452_data *data, 429c7eeea93SPeter Meerwald int val, int val2) 430c7eeea93SPeter Meerwald { 431c7eeea93SPeter Meerwald return mma8452_get_int_plus_micros_index(mma8452_samp_freq, 432686027fbSHartmut Knaack ARRAY_SIZE(mma8452_samp_freq), 433686027fbSHartmut Knaack val, val2); 434c7eeea93SPeter Meerwald } 435c7eeea93SPeter Meerwald 436686027fbSHartmut Knaack static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) 437c7eeea93SPeter Meerwald { 438c3cdd6e4SMartin Kepplinger return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales, 439c3cdd6e4SMartin Kepplinger ARRAY_SIZE(data->chip_info->mma_scales), val, val2); 440c7eeea93SPeter Meerwald } 441c7eeea93SPeter Meerwald 4421e79841aSMartin Fuzzey static int mma8452_get_hp_filter_index(struct mma8452_data *data, 4431e79841aSMartin Fuzzey int val, int val2) 4441e79841aSMartin Fuzzey { 445ed859fc1SMartin Kepplinger int i, j; 4461e79841aSMartin Fuzzey 447ed859fc1SMartin Kepplinger i = mma8452_get_odr_index(data); 448ed859fc1SMartin Kepplinger j = mma8452_get_power_mode(data); 449ed859fc1SMartin Kepplinger if (j < 0) 450ed859fc1SMartin Kepplinger return j; 451ed859fc1SMartin Kepplinger 452ed859fc1SMartin Kepplinger return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[j][i], 453ed859fc1SMartin Kepplinger ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]), val, val2); 4541e79841aSMartin Fuzzey } 4551e79841aSMartin Fuzzey 4561e79841aSMartin Fuzzey static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz) 4571e79841aSMartin Fuzzey { 458ed859fc1SMartin Kepplinger int j, i, ret; 4591e79841aSMartin Fuzzey 4601e79841aSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); 4611e79841aSMartin Fuzzey if (ret < 0) 4621e79841aSMartin Fuzzey return ret; 4631e79841aSMartin Fuzzey 4641e79841aSMartin Fuzzey i = mma8452_get_odr_index(data); 465ed859fc1SMartin Kepplinger j = mma8452_get_power_mode(data); 466ed859fc1SMartin Kepplinger if (j < 0) 467ed859fc1SMartin Kepplinger return j; 468ed859fc1SMartin Kepplinger 4691e79841aSMartin Fuzzey ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK; 470ed859fc1SMartin Kepplinger *hz = mma8452_hp_filter_cutoff[j][i][ret][0]; 471ed859fc1SMartin Kepplinger *uHz = mma8452_hp_filter_cutoff[j][i][ret][1]; 4721e79841aSMartin Fuzzey 4731e79841aSMartin Fuzzey return 0; 4741e79841aSMartin Fuzzey } 4751e79841aSMartin Fuzzey 476c7eeea93SPeter Meerwald static int mma8452_read_raw(struct iio_dev *indio_dev, 477c7eeea93SPeter Meerwald struct iio_chan_spec const *chan, 478c7eeea93SPeter Meerwald int *val, int *val2, long mask) 479c7eeea93SPeter Meerwald { 480c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 481c7eeea93SPeter Meerwald __be16 buffer[3]; 482c7eeea93SPeter Meerwald int i, ret; 483c7eeea93SPeter Meerwald 484c7eeea93SPeter Meerwald switch (mask) { 485c7eeea93SPeter Meerwald case IIO_CHAN_INFO_RAW: 4864d9b0413SAlison Schofield ret = iio_device_claim_direct_mode(indio_dev); 4874d9b0413SAlison Schofield if (ret) 4884d9b0413SAlison Schofield return ret; 489c7eeea93SPeter Meerwald 490c7eeea93SPeter Meerwald mutex_lock(&data->lock); 491c7eeea93SPeter Meerwald ret = mma8452_read(data, buffer); 492c7eeea93SPeter Meerwald mutex_unlock(&data->lock); 4934d9b0413SAlison Schofield iio_device_release_direct_mode(indio_dev); 494c7eeea93SPeter Meerwald if (ret < 0) 495c7eeea93SPeter Meerwald return ret; 496686027fbSHartmut Knaack 497c3cdd6e4SMartin Kepplinger *val = sign_extend32(be16_to_cpu( 498c3cdd6e4SMartin Kepplinger buffer[chan->scan_index]) >> chan->scan_type.shift, 499c3cdd6e4SMartin Kepplinger chan->scan_type.realbits - 1); 500686027fbSHartmut Knaack 501c7eeea93SPeter Meerwald return IIO_VAL_INT; 502c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SCALE: 503c7eeea93SPeter Meerwald i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; 504c3cdd6e4SMartin Kepplinger *val = data->chip_info->mma_scales[i][0]; 505c3cdd6e4SMartin Kepplinger *val2 = data->chip_info->mma_scales[i][1]; 506686027fbSHartmut Knaack 507c7eeea93SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 508c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SAMP_FREQ: 5095dbbd19fSMartin Fuzzey i = mma8452_get_odr_index(data); 510c7eeea93SPeter Meerwald *val = mma8452_samp_freq[i][0]; 511c7eeea93SPeter Meerwald *val2 = mma8452_samp_freq[i][1]; 512686027fbSHartmut Knaack 513c7eeea93SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 514c7eeea93SPeter Meerwald case IIO_CHAN_INFO_CALIBBIAS: 515686027fbSHartmut Knaack ret = i2c_smbus_read_byte_data(data->client, 5168b8ff3a6SMartin Kepplinger MMA8452_OFF_X + 5178b8ff3a6SMartin Kepplinger chan->scan_index); 518c7eeea93SPeter Meerwald if (ret < 0) 519c7eeea93SPeter Meerwald return ret; 520686027fbSHartmut Knaack 521c7eeea93SPeter Meerwald *val = sign_extend32(ret, 7); 522686027fbSHartmut Knaack 523c7eeea93SPeter Meerwald return IIO_VAL_INT; 5241e79841aSMartin Fuzzey case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 5251e79841aSMartin Fuzzey if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) { 5261e79841aSMartin Fuzzey ret = mma8452_read_hp_filter(data, val, val2); 5271e79841aSMartin Fuzzey if (ret < 0) 5281e79841aSMartin Fuzzey return ret; 5291e79841aSMartin Fuzzey } else { 5301e79841aSMartin Fuzzey *val = 0; 5311e79841aSMartin Fuzzey *val2 = 0; 5321e79841aSMartin Fuzzey } 533686027fbSHartmut Knaack 5341e79841aSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 535ed859fc1SMartin Kepplinger case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 536ed859fc1SMartin Kepplinger ret = mma8452_get_power_mode(data); 537ed859fc1SMartin Kepplinger if (ret < 0) 538ed859fc1SMartin Kepplinger return ret; 539ed859fc1SMartin Kepplinger 540ed859fc1SMartin Kepplinger i = mma8452_get_odr_index(data); 541ed859fc1SMartin Kepplinger 542ed859fc1SMartin Kepplinger *val = mma8452_os_ratio[ret][i]; 543ed859fc1SMartin Kepplinger return IIO_VAL_INT; 544c7eeea93SPeter Meerwald } 545686027fbSHartmut Knaack 546c7eeea93SPeter Meerwald return -EINVAL; 547c7eeea93SPeter Meerwald } 548c7eeea93SPeter Meerwald 549c7eeea93SPeter Meerwald static int mma8452_standby(struct mma8452_data *data) 550c7eeea93SPeter Meerwald { 551c7eeea93SPeter Meerwald return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, 552c7eeea93SPeter Meerwald data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); 553c7eeea93SPeter Meerwald } 554c7eeea93SPeter Meerwald 555c7eeea93SPeter Meerwald static int mma8452_active(struct mma8452_data *data) 556c7eeea93SPeter Meerwald { 557c7eeea93SPeter Meerwald return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, 558c7eeea93SPeter Meerwald data->ctrl_reg1); 559c7eeea93SPeter Meerwald } 560c7eeea93SPeter Meerwald 561e866853dSMartin Kepplinger /* returns >0 if active, 0 if in standby and <0 on error */ 562e866853dSMartin Kepplinger static int mma8452_is_active(struct mma8452_data *data) 563e866853dSMartin Kepplinger { 564e866853dSMartin Kepplinger int reg; 565e866853dSMartin Kepplinger 566e866853dSMartin Kepplinger reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG1); 567e866853dSMartin Kepplinger if (reg < 0) 568e866853dSMartin Kepplinger return reg; 569e866853dSMartin Kepplinger 570e866853dSMartin Kepplinger return reg & MMA8452_CTRL_ACTIVE; 571e866853dSMartin Kepplinger } 572e866853dSMartin Kepplinger 573c7eeea93SPeter Meerwald static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) 574c7eeea93SPeter Meerwald { 575c7eeea93SPeter Meerwald int ret; 576e866853dSMartin Kepplinger int is_active; 577c7eeea93SPeter Meerwald 578c7eeea93SPeter Meerwald mutex_lock(&data->lock); 579c7eeea93SPeter Meerwald 580e866853dSMartin Kepplinger is_active = mma8452_is_active(data); 581e866853dSMartin Kepplinger if (is_active < 0) { 582e866853dSMartin Kepplinger ret = is_active; 583e866853dSMartin Kepplinger goto fail; 584e866853dSMartin Kepplinger } 585e866853dSMartin Kepplinger 586c7eeea93SPeter Meerwald /* config can only be changed when in standby */ 587e866853dSMartin Kepplinger if (is_active > 0) { 588c7eeea93SPeter Meerwald ret = mma8452_standby(data); 589c7eeea93SPeter Meerwald if (ret < 0) 590c7eeea93SPeter Meerwald goto fail; 591e866853dSMartin Kepplinger } 592c7eeea93SPeter Meerwald 593c7eeea93SPeter Meerwald ret = i2c_smbus_write_byte_data(data->client, reg, val); 594c7eeea93SPeter Meerwald if (ret < 0) 595c7eeea93SPeter Meerwald goto fail; 596c7eeea93SPeter Meerwald 597e866853dSMartin Kepplinger if (is_active > 0) { 598c7eeea93SPeter Meerwald ret = mma8452_active(data); 599c7eeea93SPeter Meerwald if (ret < 0) 600c7eeea93SPeter Meerwald goto fail; 601e866853dSMartin Kepplinger } 602c7eeea93SPeter Meerwald 603c7eeea93SPeter Meerwald ret = 0; 604c7eeea93SPeter Meerwald fail: 605c7eeea93SPeter Meerwald mutex_unlock(&data->lock); 606686027fbSHartmut Knaack 607c7eeea93SPeter Meerwald return ret; 608c7eeea93SPeter Meerwald } 609c7eeea93SPeter Meerwald 610ed859fc1SMartin Kepplinger static int mma8452_set_power_mode(struct mma8452_data *data, u8 mode) 611ed859fc1SMartin Kepplinger { 612ed859fc1SMartin Kepplinger int reg; 613ed859fc1SMartin Kepplinger 614ed859fc1SMartin Kepplinger reg = i2c_smbus_read_byte_data(data->client, 615ed859fc1SMartin Kepplinger MMA8452_CTRL_REG2); 616ed859fc1SMartin Kepplinger if (reg < 0) 617ed859fc1SMartin Kepplinger return reg; 618ed859fc1SMartin Kepplinger 619ed859fc1SMartin Kepplinger reg &= ~MMA8452_CTRL_REG2_MODS_MASK; 620ed859fc1SMartin Kepplinger reg |= mode << MMA8452_CTRL_REG2_MODS_SHIFT; 621ed859fc1SMartin Kepplinger 622ed859fc1SMartin Kepplinger return mma8452_change_config(data, MMA8452_CTRL_REG2, reg); 623ed859fc1SMartin Kepplinger } 624ed859fc1SMartin Kepplinger 6258b8ff3a6SMartin Kepplinger /* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */ 6264b04266aSMartin Kepplinger static int mma8452_freefall_mode_enabled(struct mma8452_data *data) 6274b04266aSMartin Kepplinger { 6284b04266aSMartin Kepplinger int val; 6294b04266aSMartin Kepplinger 630605f72deSHarinath Nampally val = i2c_smbus_read_byte_data(data->client, MMA8452_FF_MT_CFG); 6314b04266aSMartin Kepplinger if (val < 0) 6324b04266aSMartin Kepplinger return val; 6334b04266aSMartin Kepplinger 6344b04266aSMartin Kepplinger return !(val & MMA8452_FF_MT_CFG_OAE); 6354b04266aSMartin Kepplinger } 6364b04266aSMartin Kepplinger 6374b04266aSMartin Kepplinger static int mma8452_set_freefall_mode(struct mma8452_data *data, bool state) 6384b04266aSMartin Kepplinger { 6394b04266aSMartin Kepplinger int val; 6404b04266aSMartin Kepplinger 6414b04266aSMartin Kepplinger if ((state && mma8452_freefall_mode_enabled(data)) || 6424b04266aSMartin Kepplinger (!state && !(mma8452_freefall_mode_enabled(data)))) 6434b04266aSMartin Kepplinger return 0; 6444b04266aSMartin Kepplinger 645605f72deSHarinath Nampally val = i2c_smbus_read_byte_data(data->client, MMA8452_FF_MT_CFG); 6464b04266aSMartin Kepplinger if (val < 0) 6474b04266aSMartin Kepplinger return val; 6484b04266aSMartin Kepplinger 6494b04266aSMartin Kepplinger if (state) { 650605f72deSHarinath Nampally val |= BIT(idx_x + MMA8452_FF_MT_CHAN_SHIFT); 651605f72deSHarinath Nampally val |= BIT(idx_y + MMA8452_FF_MT_CHAN_SHIFT); 652605f72deSHarinath Nampally val |= BIT(idx_z + MMA8452_FF_MT_CHAN_SHIFT); 6534b04266aSMartin Kepplinger val &= ~MMA8452_FF_MT_CFG_OAE; 6544b04266aSMartin Kepplinger } else { 655605f72deSHarinath Nampally val &= ~BIT(idx_x + MMA8452_FF_MT_CHAN_SHIFT); 656605f72deSHarinath Nampally val &= ~BIT(idx_y + MMA8452_FF_MT_CHAN_SHIFT); 657605f72deSHarinath Nampally val &= ~BIT(idx_z + MMA8452_FF_MT_CHAN_SHIFT); 6584b04266aSMartin Kepplinger val |= MMA8452_FF_MT_CFG_OAE; 6594b04266aSMartin Kepplinger } 6604b04266aSMartin Kepplinger 661605f72deSHarinath Nampally return mma8452_change_config(data, MMA8452_FF_MT_CFG, val); 6624b04266aSMartin Kepplinger } 6634b04266aSMartin Kepplinger 6641e79841aSMartin Fuzzey static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, 6651e79841aSMartin Fuzzey int val, int val2) 6661e79841aSMartin Fuzzey { 6671e79841aSMartin Fuzzey int i, reg; 6681e79841aSMartin Fuzzey 6691e79841aSMartin Fuzzey i = mma8452_get_hp_filter_index(data, val, val2); 6701e79841aSMartin Fuzzey if (i < 0) 671b9fddcdbSHartmut Knaack return i; 6721e79841aSMartin Fuzzey 6731e79841aSMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, 6741e79841aSMartin Fuzzey MMA8452_HP_FILTER_CUTOFF); 6751e79841aSMartin Fuzzey if (reg < 0) 6761e79841aSMartin Fuzzey return reg; 677686027fbSHartmut Knaack 6781e79841aSMartin Fuzzey reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK; 6791e79841aSMartin Fuzzey reg |= i; 6801e79841aSMartin Fuzzey 6811e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg); 6821e79841aSMartin Fuzzey } 6831e79841aSMartin Fuzzey 684c7eeea93SPeter Meerwald static int mma8452_write_raw(struct iio_dev *indio_dev, 685c7eeea93SPeter Meerwald struct iio_chan_spec const *chan, 686c7eeea93SPeter Meerwald int val, int val2, long mask) 687c7eeea93SPeter Meerwald { 688c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 6891e79841aSMartin Fuzzey int i, ret; 690c7eeea93SPeter Meerwald 69179de2ee4SJonathan Cameron ret = iio_device_claim_direct_mode(indio_dev); 69279de2ee4SJonathan Cameron if (ret) 69379de2ee4SJonathan Cameron return ret; 694c7eeea93SPeter Meerwald 695c7eeea93SPeter Meerwald switch (mask) { 696c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SAMP_FREQ: 697c7eeea93SPeter Meerwald i = mma8452_get_samp_freq_index(data, val, val2); 69879de2ee4SJonathan Cameron if (i < 0) { 69979de2ee4SJonathan Cameron ret = i; 70079de2ee4SJonathan Cameron break; 70179de2ee4SJonathan Cameron } 702c7eeea93SPeter Meerwald data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; 703c7eeea93SPeter Meerwald data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; 704686027fbSHartmut Knaack 70579de2ee4SJonathan Cameron ret = mma8452_change_config(data, MMA8452_CTRL_REG1, 706c7eeea93SPeter Meerwald data->ctrl_reg1); 70779de2ee4SJonathan Cameron break; 708c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SCALE: 709c7eeea93SPeter Meerwald i = mma8452_get_scale_index(data, val, val2); 71079de2ee4SJonathan Cameron if (i < 0) { 71179de2ee4SJonathan Cameron ret = i; 71279de2ee4SJonathan Cameron break; 71379de2ee4SJonathan Cameron } 714686027fbSHartmut Knaack 715c7eeea93SPeter Meerwald data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; 716c7eeea93SPeter Meerwald data->data_cfg |= i; 717686027fbSHartmut Knaack 71879de2ee4SJonathan Cameron ret = mma8452_change_config(data, MMA8452_DATA_CFG, 719c7eeea93SPeter Meerwald data->data_cfg); 72079de2ee4SJonathan Cameron break; 721c7eeea93SPeter Meerwald case IIO_CHAN_INFO_CALIBBIAS: 72279de2ee4SJonathan Cameron if (val < -128 || val > 127) { 72379de2ee4SJonathan Cameron ret = -EINVAL; 72479de2ee4SJonathan Cameron break; 72579de2ee4SJonathan Cameron } 726686027fbSHartmut Knaack 72779de2ee4SJonathan Cameron ret = mma8452_change_config(data, 728686027fbSHartmut Knaack MMA8452_OFF_X + chan->scan_index, 729686027fbSHartmut Knaack val); 73079de2ee4SJonathan Cameron break; 7311e79841aSMartin Fuzzey 7321e79841aSMartin Fuzzey case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 7331e79841aSMartin Fuzzey if (val == 0 && val2 == 0) { 7341e79841aSMartin Fuzzey data->data_cfg &= ~MMA8452_DATA_CFG_HPF_MASK; 7351e79841aSMartin Fuzzey } else { 7361e79841aSMartin Fuzzey data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK; 7371e79841aSMartin Fuzzey ret = mma8452_set_hp_filter_frequency(data, val, val2); 7381e79841aSMartin Fuzzey if (ret < 0) 73979de2ee4SJonathan Cameron break; 7401e79841aSMartin Fuzzey } 741686027fbSHartmut Knaack 74279de2ee4SJonathan Cameron ret = mma8452_change_config(data, MMA8452_DATA_CFG, 7431e79841aSMartin Fuzzey data->data_cfg); 74479de2ee4SJonathan Cameron break; 7451e79841aSMartin Fuzzey 746ed859fc1SMartin Kepplinger case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 747ed859fc1SMartin Kepplinger ret = mma8452_get_odr_index(data); 748ed859fc1SMartin Kepplinger 749ed859fc1SMartin Kepplinger for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) { 75079de2ee4SJonathan Cameron if (mma8452_os_ratio[i][ret] == val) { 75179de2ee4SJonathan Cameron ret = mma8452_set_power_mode(data, i); 75279de2ee4SJonathan Cameron break; 75379de2ee4SJonathan Cameron } 75479de2ee4SJonathan Cameron } 75579de2ee4SJonathan Cameron break; 75679de2ee4SJonathan Cameron default: 75779de2ee4SJonathan Cameron ret = -EINVAL; 75879de2ee4SJonathan Cameron break; 759ed859fc1SMartin Kepplinger } 760ed859fc1SMartin Kepplinger 76179de2ee4SJonathan Cameron iio_device_release_direct_mode(indio_dev); 76279de2ee4SJonathan Cameron return ret; 763c7eeea93SPeter Meerwald } 764c7eeea93SPeter Meerwald 765605f72deSHarinath Nampally static int mma8452_get_event_regs(struct mma8452_data *data, 766605f72deSHarinath Nampally const struct iio_chan_spec *chan, enum iio_event_direction dir, 767605f72deSHarinath Nampally const struct mma8452_event_regs **ev_reg) 768605f72deSHarinath Nampally { 769605f72deSHarinath Nampally if (!chan) 770605f72deSHarinath Nampally return -EINVAL; 771605f72deSHarinath Nampally 772605f72deSHarinath Nampally switch (chan->type) { 773605f72deSHarinath Nampally case IIO_ACCEL: 774605f72deSHarinath Nampally switch (dir) { 775605f72deSHarinath Nampally case IIO_EV_DIR_RISING: 776605f72deSHarinath Nampally if ((data->chip_info->all_events 777605f72deSHarinath Nampally & MMA8452_INT_TRANS) && 778605f72deSHarinath Nampally (data->chip_info->enabled_events 779605f72deSHarinath Nampally & MMA8452_INT_TRANS)) 780605f72deSHarinath Nampally *ev_reg = &ev_regs_accel_rising; 781605f72deSHarinath Nampally else 782605f72deSHarinath Nampally *ev_reg = &ev_regs_accel_falling; 783605f72deSHarinath Nampally return 0; 784605f72deSHarinath Nampally case IIO_EV_DIR_FALLING: 785605f72deSHarinath Nampally *ev_reg = &ev_regs_accel_falling; 786605f72deSHarinath Nampally return 0; 787605f72deSHarinath Nampally default: 788605f72deSHarinath Nampally return -EINVAL; 789605f72deSHarinath Nampally } 790605f72deSHarinath Nampally default: 791605f72deSHarinath Nampally return -EINVAL; 792605f72deSHarinath Nampally } 793605f72deSHarinath Nampally } 794605f72deSHarinath Nampally 79528e34278SMartin Fuzzey static int mma8452_read_thresh(struct iio_dev *indio_dev, 79628e34278SMartin Fuzzey const struct iio_chan_spec *chan, 79728e34278SMartin Fuzzey enum iio_event_type type, 79828e34278SMartin Fuzzey enum iio_event_direction dir, 79928e34278SMartin Fuzzey enum iio_event_info info, 80028e34278SMartin Fuzzey int *val, int *val2) 80128e34278SMartin Fuzzey { 80228e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 803ed859fc1SMartin Kepplinger int ret, us, power_mode; 804605f72deSHarinath Nampally const struct mma8452_event_regs *ev_regs; 805605f72deSHarinath Nampally 806605f72deSHarinath Nampally ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); 807605f72deSHarinath Nampally if (ret) 808605f72deSHarinath Nampally return ret; 80928e34278SMartin Fuzzey 8105dbbd19fSMartin Fuzzey switch (info) { 8115dbbd19fSMartin Fuzzey case IIO_EV_INFO_VALUE: 812605f72deSHarinath Nampally ret = i2c_smbus_read_byte_data(data->client, ev_regs->ev_ths); 81328e34278SMartin Fuzzey if (ret < 0) 81428e34278SMartin Fuzzey return ret; 81528e34278SMartin Fuzzey 816605f72deSHarinath Nampally *val = ret & ev_regs->ev_ths_mask; 817686027fbSHartmut Knaack 81828e34278SMartin Fuzzey return IIO_VAL_INT; 8195dbbd19fSMartin Fuzzey 8205dbbd19fSMartin Fuzzey case IIO_EV_INFO_PERIOD: 821605f72deSHarinath Nampally ret = i2c_smbus_read_byte_data(data->client, ev_regs->ev_count); 8225dbbd19fSMartin Fuzzey if (ret < 0) 8235dbbd19fSMartin Fuzzey return ret; 8245dbbd19fSMartin Fuzzey 825ed859fc1SMartin Kepplinger power_mode = mma8452_get_power_mode(data); 826ed859fc1SMartin Kepplinger if (power_mode < 0) 827ed859fc1SMartin Kepplinger return power_mode; 828ed859fc1SMartin Kepplinger 829ed859fc1SMartin Kepplinger us = ret * mma8452_transient_time_step_us[power_mode][ 8305dbbd19fSMartin Fuzzey mma8452_get_odr_index(data)]; 8315dbbd19fSMartin Fuzzey *val = us / USEC_PER_SEC; 8325dbbd19fSMartin Fuzzey *val2 = us % USEC_PER_SEC; 833686027fbSHartmut Knaack 8345dbbd19fSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 8355dbbd19fSMartin Fuzzey 8361e79841aSMartin Fuzzey case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: 8371e79841aSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, 8381e79841aSMartin Fuzzey MMA8452_TRANSIENT_CFG); 8391e79841aSMartin Fuzzey if (ret < 0) 8401e79841aSMartin Fuzzey return ret; 8411e79841aSMartin Fuzzey 8421e79841aSMartin Fuzzey if (ret & MMA8452_TRANSIENT_CFG_HPF_BYP) { 8431e79841aSMartin Fuzzey *val = 0; 8441e79841aSMartin Fuzzey *val2 = 0; 8451e79841aSMartin Fuzzey } else { 8461e79841aSMartin Fuzzey ret = mma8452_read_hp_filter(data, val, val2); 8471e79841aSMartin Fuzzey if (ret < 0) 8481e79841aSMartin Fuzzey return ret; 8491e79841aSMartin Fuzzey } 850686027fbSHartmut Knaack 8511e79841aSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 8521e79841aSMartin Fuzzey 8535dbbd19fSMartin Fuzzey default: 8545dbbd19fSMartin Fuzzey return -EINVAL; 8555dbbd19fSMartin Fuzzey } 85628e34278SMartin Fuzzey } 85728e34278SMartin Fuzzey 85828e34278SMartin Fuzzey static int mma8452_write_thresh(struct iio_dev *indio_dev, 85928e34278SMartin Fuzzey const struct iio_chan_spec *chan, 86028e34278SMartin Fuzzey enum iio_event_type type, 86128e34278SMartin Fuzzey enum iio_event_direction dir, 86228e34278SMartin Fuzzey enum iio_event_info info, 86328e34278SMartin Fuzzey int val, int val2) 86428e34278SMartin Fuzzey { 86528e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 8661e79841aSMartin Fuzzey int ret, reg, steps; 867605f72deSHarinath Nampally const struct mma8452_event_regs *ev_regs; 868605f72deSHarinath Nampally 869605f72deSHarinath Nampally ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); 870605f72deSHarinath Nampally if (ret) 871605f72deSHarinath Nampally return ret; 87228e34278SMartin Fuzzey 8735dbbd19fSMartin Fuzzey switch (info) { 8745dbbd19fSMartin Fuzzey case IIO_EV_INFO_VALUE: 875605f72deSHarinath Nampally if (val < 0 || val > ev_regs->ev_ths_mask) 87611218226SHartmut Knaack return -EINVAL; 87711218226SHartmut Knaack 878605f72deSHarinath Nampally return mma8452_change_config(data, ev_regs->ev_ths, val); 8795dbbd19fSMartin Fuzzey 8805dbbd19fSMartin Fuzzey case IIO_EV_INFO_PERIOD: 881ed859fc1SMartin Kepplinger ret = mma8452_get_power_mode(data); 882ed859fc1SMartin Kepplinger if (ret < 0) 883ed859fc1SMartin Kepplinger return ret; 884ed859fc1SMartin Kepplinger 8855dbbd19fSMartin Fuzzey steps = (val * USEC_PER_SEC + val2) / 886ed859fc1SMartin Kepplinger mma8452_transient_time_step_us[ret][ 8875dbbd19fSMartin Fuzzey mma8452_get_odr_index(data)]; 8885dbbd19fSMartin Fuzzey 88911218226SHartmut Knaack if (steps < 0 || steps > 0xff) 8905dbbd19fSMartin Fuzzey return -EINVAL; 8915dbbd19fSMartin Fuzzey 892605f72deSHarinath Nampally return mma8452_change_config(data, ev_regs->ev_count, steps); 893686027fbSHartmut Knaack 8941e79841aSMartin Fuzzey case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: 8951e79841aSMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, 8961e79841aSMartin Fuzzey MMA8452_TRANSIENT_CFG); 8971e79841aSMartin Fuzzey if (reg < 0) 8981e79841aSMartin Fuzzey return reg; 8991e79841aSMartin Fuzzey 9001e79841aSMartin Fuzzey if (val == 0 && val2 == 0) { 9011e79841aSMartin Fuzzey reg |= MMA8452_TRANSIENT_CFG_HPF_BYP; 9021e79841aSMartin Fuzzey } else { 9031e79841aSMartin Fuzzey reg &= ~MMA8452_TRANSIENT_CFG_HPF_BYP; 9041e79841aSMartin Fuzzey ret = mma8452_set_hp_filter_frequency(data, val, val2); 9051e79841aSMartin Fuzzey if (ret < 0) 9061e79841aSMartin Fuzzey return ret; 9071e79841aSMartin Fuzzey } 908686027fbSHartmut Knaack 9091e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg); 9101e79841aSMartin Fuzzey 9115dbbd19fSMartin Fuzzey default: 9125dbbd19fSMartin Fuzzey return -EINVAL; 9135dbbd19fSMartin Fuzzey } 91428e34278SMartin Fuzzey } 91528e34278SMartin Fuzzey 91628e34278SMartin Fuzzey static int mma8452_read_event_config(struct iio_dev *indio_dev, 91728e34278SMartin Fuzzey const struct iio_chan_spec *chan, 91828e34278SMartin Fuzzey enum iio_event_type type, 91928e34278SMartin Fuzzey enum iio_event_direction dir) 92028e34278SMartin Fuzzey { 92128e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 92228e34278SMartin Fuzzey int ret; 923605f72deSHarinath Nampally const struct mma8452_event_regs *ev_regs; 924605f72deSHarinath Nampally 925605f72deSHarinath Nampally ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); 926605f72deSHarinath Nampally if (ret) 927605f72deSHarinath Nampally return ret; 92828e34278SMartin Fuzzey 9294b04266aSMartin Kepplinger switch (dir) { 9304b04266aSMartin Kepplinger case IIO_EV_DIR_FALLING: 9314b04266aSMartin Kepplinger return mma8452_freefall_mode_enabled(data); 9324b04266aSMartin Kepplinger case IIO_EV_DIR_RISING: 933c3cdd6e4SMartin Kepplinger ret = i2c_smbus_read_byte_data(data->client, 934605f72deSHarinath Nampally ev_regs->ev_cfg); 93528e34278SMartin Fuzzey if (ret < 0) 93628e34278SMartin Fuzzey return ret; 93728e34278SMartin Fuzzey 9388b8ff3a6SMartin Kepplinger return !!(ret & BIT(chan->scan_index + 939605f72deSHarinath Nampally ev_regs->ev_cfg_chan_shift)); 9404b04266aSMartin Kepplinger default: 9414b04266aSMartin Kepplinger return -EINVAL; 9424b04266aSMartin Kepplinger } 94328e34278SMartin Fuzzey } 94428e34278SMartin Fuzzey 94528e34278SMartin Fuzzey static int mma8452_write_event_config(struct iio_dev *indio_dev, 94628e34278SMartin Fuzzey const struct iio_chan_spec *chan, 94728e34278SMartin Fuzzey enum iio_event_type type, 94828e34278SMartin Fuzzey enum iio_event_direction dir, 94928e34278SMartin Fuzzey int state) 95028e34278SMartin Fuzzey { 95128e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 95296c0cb2bSMartin Kepplinger int val, ret; 953605f72deSHarinath Nampally const struct mma8452_event_regs *ev_regs; 954605f72deSHarinath Nampally 955605f72deSHarinath Nampally ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); 956605f72deSHarinath Nampally if (ret) 957605f72deSHarinath Nampally return ret; 95896c0cb2bSMartin Kepplinger 95996c0cb2bSMartin Kepplinger ret = mma8452_set_runtime_pm_state(data->client, state); 96096c0cb2bSMartin Kepplinger if (ret) 96196c0cb2bSMartin Kepplinger return ret; 96228e34278SMartin Fuzzey 9634b04266aSMartin Kepplinger switch (dir) { 9644b04266aSMartin Kepplinger case IIO_EV_DIR_FALLING: 9654b04266aSMartin Kepplinger return mma8452_set_freefall_mode(data, state); 9664b04266aSMartin Kepplinger case IIO_EV_DIR_RISING: 967605f72deSHarinath Nampally val = i2c_smbus_read_byte_data(data->client, ev_regs->ev_cfg); 96828e34278SMartin Fuzzey if (val < 0) 96928e34278SMartin Fuzzey return val; 97028e34278SMartin Fuzzey 9714b04266aSMartin Kepplinger if (state) { 9724b04266aSMartin Kepplinger if (mma8452_freefall_mode_enabled(data)) { 973605f72deSHarinath Nampally val &= ~BIT(idx_x + ev_regs->ev_cfg_chan_shift); 974605f72deSHarinath Nampally val &= ~BIT(idx_y + ev_regs->ev_cfg_chan_shift); 975605f72deSHarinath Nampally val &= ~BIT(idx_z + ev_regs->ev_cfg_chan_shift); 9764b04266aSMartin Kepplinger val |= MMA8452_FF_MT_CFG_OAE; 9774b04266aSMartin Kepplinger } 978605f72deSHarinath Nampally val |= BIT(chan->scan_index + 979605f72deSHarinath Nampally ev_regs->ev_cfg_chan_shift); 9804b04266aSMartin Kepplinger } else { 9814b04266aSMartin Kepplinger if (mma8452_freefall_mode_enabled(data)) 9824b04266aSMartin Kepplinger return 0; 9834b04266aSMartin Kepplinger 984605f72deSHarinath Nampally val &= ~BIT(chan->scan_index + 985605f72deSHarinath Nampally ev_regs->ev_cfg_chan_shift); 9864b04266aSMartin Kepplinger } 98728e34278SMartin Fuzzey 988605f72deSHarinath Nampally val |= ev_regs->ev_cfg_ele; 98928e34278SMartin Fuzzey 990605f72deSHarinath Nampally return mma8452_change_config(data, ev_regs->ev_cfg, val); 9914b04266aSMartin Kepplinger default: 9924b04266aSMartin Kepplinger return -EINVAL; 9934b04266aSMartin Kepplinger } 99428e34278SMartin Fuzzey } 99528e34278SMartin Fuzzey 99628e34278SMartin Fuzzey static void mma8452_transient_interrupt(struct iio_dev *indio_dev) 99728e34278SMartin Fuzzey { 99828e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 999bc2b7dabSGregor Boirie s64 ts = iio_get_time_ns(indio_dev); 100028e34278SMartin Fuzzey int src; 100128e34278SMartin Fuzzey 1002605f72deSHarinath Nampally src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC); 100328e34278SMartin Fuzzey if (src < 0) 100428e34278SMartin Fuzzey return; 100528e34278SMartin Fuzzey 1006605f72deSHarinath Nampally if (src & MMA8452_TRANSIENT_SRC_XTRANSE) 100728e34278SMartin Fuzzey iio_push_event(indio_dev, 100828e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, 1009c5d0db06SMartin Kepplinger IIO_EV_TYPE_MAG, 101028e34278SMartin Fuzzey IIO_EV_DIR_RISING), 101128e34278SMartin Fuzzey ts); 101228e34278SMartin Fuzzey 1013605f72deSHarinath Nampally if (src & MMA8452_TRANSIENT_SRC_YTRANSE) 101428e34278SMartin Fuzzey iio_push_event(indio_dev, 101528e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y, 1016c5d0db06SMartin Kepplinger IIO_EV_TYPE_MAG, 101728e34278SMartin Fuzzey IIO_EV_DIR_RISING), 101828e34278SMartin Fuzzey ts); 101928e34278SMartin Fuzzey 1020605f72deSHarinath Nampally if (src & MMA8452_TRANSIENT_SRC_ZTRANSE) 102128e34278SMartin Fuzzey iio_push_event(indio_dev, 102228e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z, 1023c5d0db06SMartin Kepplinger IIO_EV_TYPE_MAG, 102428e34278SMartin Fuzzey IIO_EV_DIR_RISING), 102528e34278SMartin Fuzzey ts); 102628e34278SMartin Fuzzey } 102728e34278SMartin Fuzzey 102828e34278SMartin Fuzzey static irqreturn_t mma8452_interrupt(int irq, void *p) 102928e34278SMartin Fuzzey { 103028e34278SMartin Fuzzey struct iio_dev *indio_dev = p; 103128e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 1032ae6d9ce0SMartin Fuzzey int ret = IRQ_NONE; 103328e34278SMartin Fuzzey int src; 103428e34278SMartin Fuzzey 103528e34278SMartin Fuzzey src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC); 103628e34278SMartin Fuzzey if (src < 0) 103728e34278SMartin Fuzzey return IRQ_NONE; 103828e34278SMartin Fuzzey 1039605f72deSHarinath Nampally if (!(src & data->chip_info->enabled_events)) 1040605f72deSHarinath Nampally return IRQ_NONE; 1041605f72deSHarinath Nampally 1042ae6d9ce0SMartin Fuzzey if (src & MMA8452_INT_DRDY) { 1043ae6d9ce0SMartin Fuzzey iio_trigger_poll_chained(indio_dev->trig); 1044ae6d9ce0SMartin Fuzzey ret = IRQ_HANDLED; 104528e34278SMartin Fuzzey } 104628e34278SMartin Fuzzey 1047605f72deSHarinath Nampally if (src & MMA8452_INT_FF_MT) { 1048605f72deSHarinath Nampally if (mma8452_freefall_mode_enabled(data)) { 1049605f72deSHarinath Nampally s64 ts = iio_get_time_ns(indio_dev); 1050605f72deSHarinath Nampally 1051605f72deSHarinath Nampally iio_push_event(indio_dev, 1052605f72deSHarinath Nampally IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, 1053605f72deSHarinath Nampally IIO_MOD_X_AND_Y_AND_Z, 1054605f72deSHarinath Nampally IIO_EV_TYPE_MAG, 1055605f72deSHarinath Nampally IIO_EV_DIR_FALLING), 1056605f72deSHarinath Nampally ts); 1057605f72deSHarinath Nampally } 1058605f72deSHarinath Nampally ret = IRQ_HANDLED; 1059605f72deSHarinath Nampally } 1060605f72deSHarinath Nampally 1061605f72deSHarinath Nampally if (src & MMA8452_INT_TRANS) { 1062ae6d9ce0SMartin Fuzzey mma8452_transient_interrupt(indio_dev); 1063ae6d9ce0SMartin Fuzzey ret = IRQ_HANDLED; 1064ae6d9ce0SMartin Fuzzey } 1065ae6d9ce0SMartin Fuzzey 1066ae6d9ce0SMartin Fuzzey return ret; 106728e34278SMartin Fuzzey } 106828e34278SMartin Fuzzey 1069c7eeea93SPeter Meerwald static irqreturn_t mma8452_trigger_handler(int irq, void *p) 1070c7eeea93SPeter Meerwald { 1071c7eeea93SPeter Meerwald struct iio_poll_func *pf = p; 1072c7eeea93SPeter Meerwald struct iio_dev *indio_dev = pf->indio_dev; 1073c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 1074c7eeea93SPeter Meerwald u8 buffer[16]; /* 3 16-bit channels + padding + ts */ 1075c7eeea93SPeter Meerwald int ret; 1076c7eeea93SPeter Meerwald 1077c7eeea93SPeter Meerwald ret = mma8452_read(data, (__be16 *)buffer); 1078c7eeea93SPeter Meerwald if (ret < 0) 1079c7eeea93SPeter Meerwald goto done; 1080c7eeea93SPeter Meerwald 1081c7eeea93SPeter Meerwald iio_push_to_buffers_with_timestamp(indio_dev, buffer, 1082bc2b7dabSGregor Boirie iio_get_time_ns(indio_dev)); 1083c7eeea93SPeter Meerwald 1084c7eeea93SPeter Meerwald done: 1085c7eeea93SPeter Meerwald iio_trigger_notify_done(indio_dev->trig); 1086686027fbSHartmut Knaack 1087c7eeea93SPeter Meerwald return IRQ_HANDLED; 1088c7eeea93SPeter Meerwald } 1089c7eeea93SPeter Meerwald 10902a17698cSMartin Fuzzey static int mma8452_reg_access_dbg(struct iio_dev *indio_dev, 10912a17698cSMartin Fuzzey unsigned reg, unsigned writeval, 10922a17698cSMartin Fuzzey unsigned *readval) 10932a17698cSMartin Fuzzey { 10942a17698cSMartin Fuzzey int ret; 10952a17698cSMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 10962a17698cSMartin Fuzzey 10972a17698cSMartin Fuzzey if (reg > MMA8452_MAX_REG) 10982a17698cSMartin Fuzzey return -EINVAL; 10992a17698cSMartin Fuzzey 11002a17698cSMartin Fuzzey if (!readval) 11012a17698cSMartin Fuzzey return mma8452_change_config(data, reg, writeval); 11022a17698cSMartin Fuzzey 11032a17698cSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, reg); 11042a17698cSMartin Fuzzey if (ret < 0) 11052a17698cSMartin Fuzzey return ret; 11062a17698cSMartin Fuzzey 11072a17698cSMartin Fuzzey *readval = ret; 11082a17698cSMartin Fuzzey 11092a17698cSMartin Fuzzey return 0; 11102a17698cSMartin Fuzzey } 11112a17698cSMartin Fuzzey 11124b04266aSMartin Kepplinger static const struct iio_event_spec mma8452_freefall_event[] = { 11134b04266aSMartin Kepplinger { 11144b04266aSMartin Kepplinger .type = IIO_EV_TYPE_MAG, 11154b04266aSMartin Kepplinger .dir = IIO_EV_DIR_FALLING, 11164b04266aSMartin Kepplinger .mask_separate = BIT(IIO_EV_INFO_ENABLE), 11174b04266aSMartin Kepplinger .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 11184b04266aSMartin Kepplinger BIT(IIO_EV_INFO_PERIOD) | 11194b04266aSMartin Kepplinger BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB) 11204b04266aSMartin Kepplinger }, 11214b04266aSMartin Kepplinger }; 11224b04266aSMartin Kepplinger 11234b04266aSMartin Kepplinger static const struct iio_event_spec mma8652_freefall_event[] = { 11244b04266aSMartin Kepplinger { 11254b04266aSMartin Kepplinger .type = IIO_EV_TYPE_MAG, 11264b04266aSMartin Kepplinger .dir = IIO_EV_DIR_FALLING, 11274b04266aSMartin Kepplinger .mask_separate = BIT(IIO_EV_INFO_ENABLE), 11284b04266aSMartin Kepplinger .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 11294b04266aSMartin Kepplinger BIT(IIO_EV_INFO_PERIOD) 11304b04266aSMartin Kepplinger }, 11314b04266aSMartin Kepplinger }; 11324b04266aSMartin Kepplinger 113328e34278SMartin Fuzzey static const struct iio_event_spec mma8452_transient_event[] = { 113428e34278SMartin Fuzzey { 1135c5d0db06SMartin Kepplinger .type = IIO_EV_TYPE_MAG, 113628e34278SMartin Fuzzey .dir = IIO_EV_DIR_RISING, 113728e34278SMartin Fuzzey .mask_separate = BIT(IIO_EV_INFO_ENABLE), 11385dbbd19fSMartin Fuzzey .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 11391e79841aSMartin Fuzzey BIT(IIO_EV_INFO_PERIOD) | 11401e79841aSMartin Fuzzey BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB) 114128e34278SMartin Fuzzey }, 114228e34278SMartin Fuzzey }; 114328e34278SMartin Fuzzey 114460f562e7SMartin Kepplinger static const struct iio_event_spec mma8452_motion_event[] = { 114560f562e7SMartin Kepplinger { 114660f562e7SMartin Kepplinger .type = IIO_EV_TYPE_MAG, 114760f562e7SMartin Kepplinger .dir = IIO_EV_DIR_RISING, 114860f562e7SMartin Kepplinger .mask_separate = BIT(IIO_EV_INFO_ENABLE), 114960f562e7SMartin Kepplinger .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 115060f562e7SMartin Kepplinger BIT(IIO_EV_INFO_PERIOD) 115160f562e7SMartin Kepplinger }, 115260f562e7SMartin Kepplinger }; 115360f562e7SMartin Kepplinger 115428e34278SMartin Fuzzey /* 115528e34278SMartin Fuzzey * Threshold is configured in fixed 8G/127 steps regardless of 115628e34278SMartin Fuzzey * currently selected scale for measurement. 115728e34278SMartin Fuzzey */ 115828e34278SMartin Fuzzey static IIO_CONST_ATTR_NAMED(accel_transient_scale, in_accel_scale, "0.617742"); 115928e34278SMartin Fuzzey 116028e34278SMartin Fuzzey static struct attribute *mma8452_event_attributes[] = { 116128e34278SMartin Fuzzey &iio_const_attr_accel_transient_scale.dev_attr.attr, 116228e34278SMartin Fuzzey NULL, 116328e34278SMartin Fuzzey }; 116428e34278SMartin Fuzzey 116528e34278SMartin Fuzzey static struct attribute_group mma8452_event_attribute_group = { 116628e34278SMartin Fuzzey .attrs = mma8452_event_attributes, 116728e34278SMartin Fuzzey }; 116828e34278SMartin Fuzzey 11694b04266aSMartin Kepplinger #define MMA8452_FREEFALL_CHANNEL(modifier) { \ 11704b04266aSMartin Kepplinger .type = IIO_ACCEL, \ 11714b04266aSMartin Kepplinger .modified = 1, \ 11724b04266aSMartin Kepplinger .channel2 = modifier, \ 11734b04266aSMartin Kepplinger .scan_index = -1, \ 11744b04266aSMartin Kepplinger .event_spec = mma8452_freefall_event, \ 11754b04266aSMartin Kepplinger .num_event_specs = ARRAY_SIZE(mma8452_freefall_event), \ 11764b04266aSMartin Kepplinger } 11774b04266aSMartin Kepplinger 11784b04266aSMartin Kepplinger #define MMA8652_FREEFALL_CHANNEL(modifier) { \ 11794b04266aSMartin Kepplinger .type = IIO_ACCEL, \ 11804b04266aSMartin Kepplinger .modified = 1, \ 11814b04266aSMartin Kepplinger .channel2 = modifier, \ 11824b04266aSMartin Kepplinger .scan_index = -1, \ 11834b04266aSMartin Kepplinger .event_spec = mma8652_freefall_event, \ 11844b04266aSMartin Kepplinger .num_event_specs = ARRAY_SIZE(mma8652_freefall_event), \ 11854b04266aSMartin Kepplinger } 11864b04266aSMartin Kepplinger 1187c3cdd6e4SMartin Kepplinger #define MMA8452_CHANNEL(axis, idx, bits) { \ 1188c7eeea93SPeter Meerwald .type = IIO_ACCEL, \ 1189c7eeea93SPeter Meerwald .modified = 1, \ 1190c7eeea93SPeter Meerwald .channel2 = IIO_MOD_##axis, \ 1191c7eeea93SPeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 1192c7eeea93SPeter Meerwald BIT(IIO_CHAN_INFO_CALIBBIAS), \ 1193c7eeea93SPeter Meerwald .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 11941e79841aSMartin Fuzzey BIT(IIO_CHAN_INFO_SCALE) | \ 1195ed859fc1SMartin Kepplinger BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) | \ 1196ed859fc1SMartin Kepplinger BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ 1197c7eeea93SPeter Meerwald .scan_index = idx, \ 1198c7eeea93SPeter Meerwald .scan_type = { \ 1199c7eeea93SPeter Meerwald .sign = 's', \ 1200c3cdd6e4SMartin Kepplinger .realbits = (bits), \ 1201c7eeea93SPeter Meerwald .storagebits = 16, \ 1202c3cdd6e4SMartin Kepplinger .shift = 16 - (bits), \ 1203c7eeea93SPeter Meerwald .endianness = IIO_BE, \ 1204c7eeea93SPeter Meerwald }, \ 120528e34278SMartin Fuzzey .event_spec = mma8452_transient_event, \ 120628e34278SMartin Fuzzey .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \ 1207c7eeea93SPeter Meerwald } 1208c7eeea93SPeter Meerwald 1209417e008bSMartin Kepplinger #define MMA8652_CHANNEL(axis, idx, bits) { \ 1210417e008bSMartin Kepplinger .type = IIO_ACCEL, \ 1211417e008bSMartin Kepplinger .modified = 1, \ 1212417e008bSMartin Kepplinger .channel2 = IIO_MOD_##axis, \ 1213417e008bSMartin Kepplinger .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 1214417e008bSMartin Kepplinger BIT(IIO_CHAN_INFO_CALIBBIAS), \ 1215417e008bSMartin Kepplinger .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 1216ed859fc1SMartin Kepplinger BIT(IIO_CHAN_INFO_SCALE) | \ 1217ed859fc1SMartin Kepplinger BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ 1218417e008bSMartin Kepplinger .scan_index = idx, \ 1219417e008bSMartin Kepplinger .scan_type = { \ 1220417e008bSMartin Kepplinger .sign = 's', \ 1221417e008bSMartin Kepplinger .realbits = (bits), \ 1222417e008bSMartin Kepplinger .storagebits = 16, \ 1223417e008bSMartin Kepplinger .shift = 16 - (bits), \ 1224417e008bSMartin Kepplinger .endianness = IIO_BE, \ 1225417e008bSMartin Kepplinger }, \ 1226417e008bSMartin Kepplinger .event_spec = mma8452_motion_event, \ 1227417e008bSMartin Kepplinger .num_event_specs = ARRAY_SIZE(mma8452_motion_event), \ 1228417e008bSMartin Kepplinger } 1229417e008bSMartin Kepplinger 1230244a93f6SMartin Kepplinger static const struct iio_chan_spec mma8451_channels[] = { 1231244a93f6SMartin Kepplinger MMA8452_CHANNEL(X, idx_x, 14), 1232244a93f6SMartin Kepplinger MMA8452_CHANNEL(Y, idx_y, 14), 1233244a93f6SMartin Kepplinger MMA8452_CHANNEL(Z, idx_z, 14), 1234244a93f6SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 1235244a93f6SMartin Kepplinger MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1236244a93f6SMartin Kepplinger }; 1237244a93f6SMartin Kepplinger 1238c7eeea93SPeter Meerwald static const struct iio_chan_spec mma8452_channels[] = { 1239e60378c1SMartin Kepplinger MMA8452_CHANNEL(X, idx_x, 12), 1240e60378c1SMartin Kepplinger MMA8452_CHANNEL(Y, idx_y, 12), 1241e60378c1SMartin Kepplinger MMA8452_CHANNEL(Z, idx_z, 12), 1242e60378c1SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 12434b04266aSMartin Kepplinger MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1244c7eeea93SPeter Meerwald }; 1245c7eeea93SPeter Meerwald 1246c5ea1b58SMartin Kepplinger static const struct iio_chan_spec mma8453_channels[] = { 1247e60378c1SMartin Kepplinger MMA8452_CHANNEL(X, idx_x, 10), 1248e60378c1SMartin Kepplinger MMA8452_CHANNEL(Y, idx_y, 10), 1249e60378c1SMartin Kepplinger MMA8452_CHANNEL(Z, idx_z, 10), 1250e60378c1SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 12514b04266aSMartin Kepplinger MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1252c5ea1b58SMartin Kepplinger }; 1253c5ea1b58SMartin Kepplinger 1254417e008bSMartin Kepplinger static const struct iio_chan_spec mma8652_channels[] = { 1255e60378c1SMartin Kepplinger MMA8652_CHANNEL(X, idx_x, 12), 1256e60378c1SMartin Kepplinger MMA8652_CHANNEL(Y, idx_y, 12), 1257e60378c1SMartin Kepplinger MMA8652_CHANNEL(Z, idx_z, 12), 1258e60378c1SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 12594b04266aSMartin Kepplinger MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1260417e008bSMartin Kepplinger }; 1261417e008bSMartin Kepplinger 1262417e008bSMartin Kepplinger static const struct iio_chan_spec mma8653_channels[] = { 1263e60378c1SMartin Kepplinger MMA8652_CHANNEL(X, idx_x, 10), 1264e60378c1SMartin Kepplinger MMA8652_CHANNEL(Y, idx_y, 10), 1265e60378c1SMartin Kepplinger MMA8652_CHANNEL(Z, idx_z, 10), 1266e60378c1SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 12674b04266aSMartin Kepplinger MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1268417e008bSMartin Kepplinger }; 1269417e008bSMartin Kepplinger 1270c3cdd6e4SMartin Kepplinger enum { 1271244a93f6SMartin Kepplinger mma8451, 1272c3cdd6e4SMartin Kepplinger mma8452, 1273c5ea1b58SMartin Kepplinger mma8453, 1274417e008bSMartin Kepplinger mma8652, 1275417e008bSMartin Kepplinger mma8653, 1276e8731180SMartin Kepplinger fxls8471, 1277c3cdd6e4SMartin Kepplinger }; 1278c3cdd6e4SMartin Kepplinger 1279c3cdd6e4SMartin Kepplinger static const struct mma_chip_info mma_chip_info_table[] = { 1280244a93f6SMartin Kepplinger [mma8451] = { 1281244a93f6SMartin Kepplinger .chip_id = MMA8451_DEVICE_ID, 1282244a93f6SMartin Kepplinger .channels = mma8451_channels, 1283244a93f6SMartin Kepplinger .num_channels = ARRAY_SIZE(mma8451_channels), 1284c3cdd6e4SMartin Kepplinger /* 1285c3cdd6e4SMartin Kepplinger * Hardware has fullscale of -2G, -4G, -8G corresponding to 1286244a93f6SMartin Kepplinger * raw value -8192 for 14 bit, -2048 for 12 bit or -512 for 10 1287244a93f6SMartin Kepplinger * bit. 1288c3cdd6e4SMartin Kepplinger * The userspace interface uses m/s^2 and we declare micro units 1289c3cdd6e4SMartin Kepplinger * So scale factor for 12 bit here is given by: 1290c3cdd6e4SMartin Kepplinger * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 1291c3cdd6e4SMartin Kepplinger */ 1292244a93f6SMartin Kepplinger .mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} }, 1293605f72deSHarinath Nampally /* 1294605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1295605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1296605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1297605f72deSHarinath Nampally */ 1298605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1299605f72deSHarinath Nampally MMA8452_INT_TRANS | 1300605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1301605f72deSHarinath Nampally .enabled_events = MMA8452_INT_TRANS | 1302605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1303244a93f6SMartin Kepplinger }, 1304244a93f6SMartin Kepplinger [mma8452] = { 1305244a93f6SMartin Kepplinger .chip_id = MMA8452_DEVICE_ID, 1306244a93f6SMartin Kepplinger .channels = mma8452_channels, 1307244a93f6SMartin Kepplinger .num_channels = ARRAY_SIZE(mma8452_channels), 1308c3cdd6e4SMartin Kepplinger .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, 1309605f72deSHarinath Nampally /* 1310605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1311605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1312605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1313605f72deSHarinath Nampally */ 1314605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1315605f72deSHarinath Nampally MMA8452_INT_TRANS | 1316605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1317605f72deSHarinath Nampally .enabled_events = MMA8452_INT_TRANS | 1318605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1319c3cdd6e4SMartin Kepplinger }, 1320c5ea1b58SMartin Kepplinger [mma8453] = { 1321c5ea1b58SMartin Kepplinger .chip_id = MMA8453_DEVICE_ID, 1322c5ea1b58SMartin Kepplinger .channels = mma8453_channels, 1323c5ea1b58SMartin Kepplinger .num_channels = ARRAY_SIZE(mma8453_channels), 1324c5ea1b58SMartin Kepplinger .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, 1325605f72deSHarinath Nampally /* 1326605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1327605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1328605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1329605f72deSHarinath Nampally */ 1330605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1331605f72deSHarinath Nampally MMA8452_INT_TRANS | 1332605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1333605f72deSHarinath Nampally .enabled_events = MMA8452_INT_TRANS | 1334605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1335c5ea1b58SMartin Kepplinger }, 1336417e008bSMartin Kepplinger [mma8652] = { 1337417e008bSMartin Kepplinger .chip_id = MMA8652_DEVICE_ID, 1338417e008bSMartin Kepplinger .channels = mma8652_channels, 1339417e008bSMartin Kepplinger .num_channels = ARRAY_SIZE(mma8652_channels), 1340417e008bSMartin Kepplinger .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, 1341605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1342605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1343605f72deSHarinath Nampally .enabled_events = MMA8452_INT_FF_MT, 1344417e008bSMartin Kepplinger }, 1345417e008bSMartin Kepplinger [mma8653] = { 1346417e008bSMartin Kepplinger .chip_id = MMA8653_DEVICE_ID, 1347417e008bSMartin Kepplinger .channels = mma8653_channels, 1348417e008bSMartin Kepplinger .num_channels = ARRAY_SIZE(mma8653_channels), 1349417e008bSMartin Kepplinger .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, 1350605f72deSHarinath Nampally /* 1351605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1352605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1353605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1354605f72deSHarinath Nampally */ 1355605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1356605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1357605f72deSHarinath Nampally .enabled_events = MMA8452_INT_FF_MT, 1358417e008bSMartin Kepplinger }, 1359e8731180SMartin Kepplinger [fxls8471] = { 1360e8731180SMartin Kepplinger .chip_id = FXLS8471_DEVICE_ID, 1361e8731180SMartin Kepplinger .channels = mma8451_channels, 1362e8731180SMartin Kepplinger .num_channels = ARRAY_SIZE(mma8451_channels), 1363e8731180SMartin Kepplinger .mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} }, 1364605f72deSHarinath Nampally /* 1365605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1366605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1367605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1368605f72deSHarinath Nampally */ 1369605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1370605f72deSHarinath Nampally MMA8452_INT_TRANS | 1371605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1372605f72deSHarinath Nampally .enabled_events = MMA8452_INT_TRANS | 1373605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1374e8731180SMartin Kepplinger }, 1375c3cdd6e4SMartin Kepplinger }; 1376c3cdd6e4SMartin Kepplinger 1377c7eeea93SPeter Meerwald static struct attribute *mma8452_attributes[] = { 1378c7eeea93SPeter Meerwald &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 1379c7eeea93SPeter Meerwald &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 13801e79841aSMartin Fuzzey &iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr, 1381ed859fc1SMartin Kepplinger &iio_dev_attr_in_accel_oversampling_ratio_available.dev_attr.attr, 1382c7eeea93SPeter Meerwald NULL 1383c7eeea93SPeter Meerwald }; 1384c7eeea93SPeter Meerwald 1385c7eeea93SPeter Meerwald static const struct attribute_group mma8452_group = { 1386c7eeea93SPeter Meerwald .attrs = mma8452_attributes, 1387c7eeea93SPeter Meerwald }; 1388c7eeea93SPeter Meerwald 1389c7eeea93SPeter Meerwald static const struct iio_info mma8452_info = { 1390c7eeea93SPeter Meerwald .attrs = &mma8452_group, 1391c7eeea93SPeter Meerwald .read_raw = &mma8452_read_raw, 1392c7eeea93SPeter Meerwald .write_raw = &mma8452_write_raw, 139328e34278SMartin Fuzzey .event_attrs = &mma8452_event_attribute_group, 139428e34278SMartin Fuzzey .read_event_value = &mma8452_read_thresh, 139528e34278SMartin Fuzzey .write_event_value = &mma8452_write_thresh, 139628e34278SMartin Fuzzey .read_event_config = &mma8452_read_event_config, 139728e34278SMartin Fuzzey .write_event_config = &mma8452_write_event_config, 13982a17698cSMartin Fuzzey .debugfs_reg_access = &mma8452_reg_access_dbg, 1399c7eeea93SPeter Meerwald }; 1400c7eeea93SPeter Meerwald 1401c7eeea93SPeter Meerwald static const unsigned long mma8452_scan_masks[] = {0x7, 0}; 1402c7eeea93SPeter Meerwald 1403ae6d9ce0SMartin Fuzzey static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig, 1404ae6d9ce0SMartin Fuzzey bool state) 1405ae6d9ce0SMartin Fuzzey { 1406ae6d9ce0SMartin Fuzzey struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 1407ae6d9ce0SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 140896c0cb2bSMartin Kepplinger int reg, ret; 140996c0cb2bSMartin Kepplinger 141096c0cb2bSMartin Kepplinger ret = mma8452_set_runtime_pm_state(data->client, state); 141196c0cb2bSMartin Kepplinger if (ret) 141296c0cb2bSMartin Kepplinger return ret; 1413ae6d9ce0SMartin Fuzzey 1414ae6d9ce0SMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4); 1415ae6d9ce0SMartin Fuzzey if (reg < 0) 1416ae6d9ce0SMartin Fuzzey return reg; 1417ae6d9ce0SMartin Fuzzey 1418ae6d9ce0SMartin Fuzzey if (state) 1419ae6d9ce0SMartin Fuzzey reg |= MMA8452_INT_DRDY; 1420ae6d9ce0SMartin Fuzzey else 1421ae6d9ce0SMartin Fuzzey reg &= ~MMA8452_INT_DRDY; 1422ae6d9ce0SMartin Fuzzey 1423ae6d9ce0SMartin Fuzzey return mma8452_change_config(data, MMA8452_CTRL_REG4, reg); 1424ae6d9ce0SMartin Fuzzey } 1425ae6d9ce0SMartin Fuzzey 1426ae6d9ce0SMartin Fuzzey static const struct iio_trigger_ops mma8452_trigger_ops = { 1427ae6d9ce0SMartin Fuzzey .set_trigger_state = mma8452_data_rdy_trigger_set_state, 142819808e04SLars-Peter Clausen .validate_device = iio_trigger_validate_own_device, 1429ae6d9ce0SMartin Fuzzey }; 1430ae6d9ce0SMartin Fuzzey 1431ae6d9ce0SMartin Fuzzey static int mma8452_trigger_setup(struct iio_dev *indio_dev) 1432ae6d9ce0SMartin Fuzzey { 1433ae6d9ce0SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 1434ae6d9ce0SMartin Fuzzey struct iio_trigger *trig; 1435ae6d9ce0SMartin Fuzzey int ret; 1436ae6d9ce0SMartin Fuzzey 1437ae6d9ce0SMartin Fuzzey trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d", 1438ae6d9ce0SMartin Fuzzey indio_dev->name, 1439ae6d9ce0SMartin Fuzzey indio_dev->id); 1440ae6d9ce0SMartin Fuzzey if (!trig) 1441ae6d9ce0SMartin Fuzzey return -ENOMEM; 1442ae6d9ce0SMartin Fuzzey 1443ae6d9ce0SMartin Fuzzey trig->dev.parent = &data->client->dev; 1444ae6d9ce0SMartin Fuzzey trig->ops = &mma8452_trigger_ops; 1445ae6d9ce0SMartin Fuzzey iio_trigger_set_drvdata(trig, indio_dev); 1446ae6d9ce0SMartin Fuzzey 1447ae6d9ce0SMartin Fuzzey ret = iio_trigger_register(trig); 1448ae6d9ce0SMartin Fuzzey if (ret) 1449ae6d9ce0SMartin Fuzzey return ret; 1450ae6d9ce0SMartin Fuzzey 1451ae6d9ce0SMartin Fuzzey indio_dev->trig = trig; 1452686027fbSHartmut Knaack 1453ae6d9ce0SMartin Fuzzey return 0; 1454ae6d9ce0SMartin Fuzzey } 1455ae6d9ce0SMartin Fuzzey 1456ae6d9ce0SMartin Fuzzey static void mma8452_trigger_cleanup(struct iio_dev *indio_dev) 1457ae6d9ce0SMartin Fuzzey { 1458ae6d9ce0SMartin Fuzzey if (indio_dev->trig) 1459ae6d9ce0SMartin Fuzzey iio_trigger_unregister(indio_dev->trig); 1460ae6d9ce0SMartin Fuzzey } 1461ae6d9ce0SMartin Fuzzey 1462ecabae71SMartin Fuzzey static int mma8452_reset(struct i2c_client *client) 1463ecabae71SMartin Fuzzey { 1464ecabae71SMartin Fuzzey int i; 1465ecabae71SMartin Fuzzey int ret; 1466ecabae71SMartin Fuzzey 1467ecabae71SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2, 1468ecabae71SMartin Fuzzey MMA8452_CTRL_REG2_RST); 1469ecabae71SMartin Fuzzey if (ret < 0) 1470ecabae71SMartin Fuzzey return ret; 1471ecabae71SMartin Fuzzey 1472ecabae71SMartin Fuzzey for (i = 0; i < 10; i++) { 1473ecabae71SMartin Fuzzey usleep_range(100, 200); 1474ecabae71SMartin Fuzzey ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2); 1475ecabae71SMartin Fuzzey if (ret == -EIO) 1476ecabae71SMartin Fuzzey continue; /* I2C comm reset */ 1477ecabae71SMartin Fuzzey if (ret < 0) 1478ecabae71SMartin Fuzzey return ret; 1479ecabae71SMartin Fuzzey if (!(ret & MMA8452_CTRL_REG2_RST)) 1480ecabae71SMartin Fuzzey return 0; 1481ecabae71SMartin Fuzzey } 1482ecabae71SMartin Fuzzey 1483ecabae71SMartin Fuzzey return -ETIMEDOUT; 1484ecabae71SMartin Fuzzey } 1485ecabae71SMartin Fuzzey 1486c3cdd6e4SMartin Kepplinger static const struct of_device_id mma8452_dt_ids[] = { 1487244a93f6SMartin Kepplinger { .compatible = "fsl,mma8451", .data = &mma_chip_info_table[mma8451] }, 1488c3cdd6e4SMartin Kepplinger { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] }, 1489c5ea1b58SMartin Kepplinger { .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] }, 1490417e008bSMartin Kepplinger { .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] }, 1491417e008bSMartin Kepplinger { .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] }, 1492e8731180SMartin Kepplinger { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] }, 1493c3cdd6e4SMartin Kepplinger { } 1494c3cdd6e4SMartin Kepplinger }; 1495c3cdd6e4SMartin Kepplinger MODULE_DEVICE_TABLE(of, mma8452_dt_ids); 1496c3cdd6e4SMartin Kepplinger 1497c7eeea93SPeter Meerwald static int mma8452_probe(struct i2c_client *client, 1498c7eeea93SPeter Meerwald const struct i2c_device_id *id) 1499c7eeea93SPeter Meerwald { 1500c7eeea93SPeter Meerwald struct mma8452_data *data; 1501c7eeea93SPeter Meerwald struct iio_dev *indio_dev; 1502c7eeea93SPeter Meerwald int ret; 1503c3cdd6e4SMartin Kepplinger const struct of_device_id *match; 1504c7eeea93SPeter Meerwald 1505c3cdd6e4SMartin Kepplinger match = of_match_device(mma8452_dt_ids, &client->dev); 1506c3cdd6e4SMartin Kepplinger if (!match) { 1507c3cdd6e4SMartin Kepplinger dev_err(&client->dev, "unknown device model\n"); 1508c3cdd6e4SMartin Kepplinger return -ENODEV; 1509c3cdd6e4SMartin Kepplinger } 1510c3cdd6e4SMartin Kepplinger 1511c7eeea93SPeter Meerwald indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 1512c7eeea93SPeter Meerwald if (!indio_dev) 1513c7eeea93SPeter Meerwald return -ENOMEM; 1514c7eeea93SPeter Meerwald 1515c7eeea93SPeter Meerwald data = iio_priv(indio_dev); 1516c7eeea93SPeter Meerwald data->client = client; 1517c7eeea93SPeter Meerwald mutex_init(&data->lock); 1518c3cdd6e4SMartin Kepplinger data->chip_info = match->data; 1519c3cdd6e4SMartin Kepplinger 1520417e008bSMartin Kepplinger ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); 1521417e008bSMartin Kepplinger if (ret < 0) 1522417e008bSMartin Kepplinger return ret; 1523417e008bSMartin Kepplinger 1524417e008bSMartin Kepplinger switch (ret) { 1525244a93f6SMartin Kepplinger case MMA8451_DEVICE_ID: 1526417e008bSMartin Kepplinger case MMA8452_DEVICE_ID: 1527417e008bSMartin Kepplinger case MMA8453_DEVICE_ID: 1528417e008bSMartin Kepplinger case MMA8652_DEVICE_ID: 1529417e008bSMartin Kepplinger case MMA8653_DEVICE_ID: 1530e8731180SMartin Kepplinger case FXLS8471_DEVICE_ID: 1531417e008bSMartin Kepplinger if (ret == data->chip_info->chip_id) 1532417e008bSMartin Kepplinger break; 1533417e008bSMartin Kepplinger default: 1534417e008bSMartin Kepplinger return -ENODEV; 1535417e008bSMartin Kepplinger } 1536417e008bSMartin Kepplinger 1537c3cdd6e4SMartin Kepplinger dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", 1538c3cdd6e4SMartin Kepplinger match->compatible, data->chip_info->chip_id); 1539c7eeea93SPeter Meerwald 1540c7eeea93SPeter Meerwald i2c_set_clientdata(client, indio_dev); 1541c7eeea93SPeter Meerwald indio_dev->info = &mma8452_info; 1542c7eeea93SPeter Meerwald indio_dev->name = id->name; 1543c7eeea93SPeter Meerwald indio_dev->dev.parent = &client->dev; 1544c7eeea93SPeter Meerwald indio_dev->modes = INDIO_DIRECT_MODE; 1545c3cdd6e4SMartin Kepplinger indio_dev->channels = data->chip_info->channels; 1546c3cdd6e4SMartin Kepplinger indio_dev->num_channels = data->chip_info->num_channels; 1547c7eeea93SPeter Meerwald indio_dev->available_scan_masks = mma8452_scan_masks; 1548c7eeea93SPeter Meerwald 1549ecabae71SMartin Fuzzey ret = mma8452_reset(client); 1550c7eeea93SPeter Meerwald if (ret < 0) 1551c7eeea93SPeter Meerwald return ret; 1552c7eeea93SPeter Meerwald 1553c7eeea93SPeter Meerwald data->data_cfg = MMA8452_DATA_CFG_FS_2G; 1554c7eeea93SPeter Meerwald ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, 1555c7eeea93SPeter Meerwald data->data_cfg); 1556c7eeea93SPeter Meerwald if (ret < 0) 1557c7eeea93SPeter Meerwald return ret; 1558c7eeea93SPeter Meerwald 155928e34278SMartin Fuzzey /* 156028e34278SMartin Fuzzey * By default set transient threshold to max to avoid events if 156128e34278SMartin Fuzzey * enabling without configuring threshold. 156228e34278SMartin Fuzzey */ 156328e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS, 156428e34278SMartin Fuzzey MMA8452_TRANSIENT_THS_MASK); 156528e34278SMartin Fuzzey if (ret < 0) 156628e34278SMartin Fuzzey return ret; 156728e34278SMartin Fuzzey 156828e34278SMartin Fuzzey if (client->irq) { 1569d2a3e093SMartin Kepplinger int irq2; 157028e34278SMartin Fuzzey 1571d2a3e093SMartin Kepplinger irq2 = of_irq_get_byname(client->dev.of_node, "INT2"); 1572d2a3e093SMartin Kepplinger 1573d2a3e093SMartin Kepplinger if (irq2 == client->irq) { 1574d2a3e093SMartin Kepplinger dev_dbg(&client->dev, "using interrupt line INT2\n"); 1575d2a3e093SMartin Kepplinger } else { 157628e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, 157728e34278SMartin Fuzzey MMA8452_CTRL_REG5, 1578605f72deSHarinath Nampally data->chip_info->all_events); 157928e34278SMartin Fuzzey if (ret < 0) 158028e34278SMartin Fuzzey return ret; 158128e34278SMartin Fuzzey 1582d2a3e093SMartin Kepplinger dev_dbg(&client->dev, "using interrupt line INT1\n"); 1583d2a3e093SMartin Kepplinger } 1584d2a3e093SMartin Kepplinger 158528e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, 158628e34278SMartin Fuzzey MMA8452_CTRL_REG4, 1587605f72deSHarinath Nampally data->chip_info->enabled_events); 1588ae6d9ce0SMartin Fuzzey if (ret < 0) 1589ae6d9ce0SMartin Fuzzey return ret; 1590ae6d9ce0SMartin Fuzzey 1591ae6d9ce0SMartin Fuzzey ret = mma8452_trigger_setup(indio_dev); 159228e34278SMartin Fuzzey if (ret < 0) 159328e34278SMartin Fuzzey return ret; 159428e34278SMartin Fuzzey } 159528e34278SMartin Fuzzey 1596ecabae71SMartin Fuzzey data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | 1597ecabae71SMartin Fuzzey (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); 1598ecabae71SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1, 1599ecabae71SMartin Fuzzey data->ctrl_reg1); 1600ecabae71SMartin Fuzzey if (ret < 0) 1601ae6d9ce0SMartin Fuzzey goto trigger_cleanup; 1602ecabae71SMartin Fuzzey 1603c7eeea93SPeter Meerwald ret = iio_triggered_buffer_setup(indio_dev, NULL, 1604c7eeea93SPeter Meerwald mma8452_trigger_handler, NULL); 1605c7eeea93SPeter Meerwald if (ret < 0) 1606ae6d9ce0SMartin Fuzzey goto trigger_cleanup; 1607c7eeea93SPeter Meerwald 160828e34278SMartin Fuzzey if (client->irq) { 160928e34278SMartin Fuzzey ret = devm_request_threaded_irq(&client->dev, 161028e34278SMartin Fuzzey client->irq, 161128e34278SMartin Fuzzey NULL, mma8452_interrupt, 161228e34278SMartin Fuzzey IRQF_TRIGGER_LOW | IRQF_ONESHOT, 161328e34278SMartin Fuzzey client->name, indio_dev); 161428e34278SMartin Fuzzey if (ret) 161528e34278SMartin Fuzzey goto buffer_cleanup; 161628e34278SMartin Fuzzey } 161728e34278SMartin Fuzzey 161896c0cb2bSMartin Kepplinger ret = pm_runtime_set_active(&client->dev); 161996c0cb2bSMartin Kepplinger if (ret < 0) 162096c0cb2bSMartin Kepplinger goto buffer_cleanup; 162196c0cb2bSMartin Kepplinger 162296c0cb2bSMartin Kepplinger pm_runtime_enable(&client->dev); 162396c0cb2bSMartin Kepplinger pm_runtime_set_autosuspend_delay(&client->dev, 162496c0cb2bSMartin Kepplinger MMA8452_AUTO_SUSPEND_DELAY_MS); 162596c0cb2bSMartin Kepplinger pm_runtime_use_autosuspend(&client->dev); 162696c0cb2bSMartin Kepplinger 1627c7eeea93SPeter Meerwald ret = iio_device_register(indio_dev); 1628c7eeea93SPeter Meerwald if (ret < 0) 1629c7eeea93SPeter Meerwald goto buffer_cleanup; 163028e34278SMartin Fuzzey 16314b04266aSMartin Kepplinger ret = mma8452_set_freefall_mode(data, false); 16321a965d40SBijosh Thykkoottathil if (ret < 0) 16331a965d40SBijosh Thykkoottathil goto buffer_cleanup; 16344b04266aSMartin Kepplinger 1635c7eeea93SPeter Meerwald return 0; 1636c7eeea93SPeter Meerwald 1637c7eeea93SPeter Meerwald buffer_cleanup: 1638c7eeea93SPeter Meerwald iio_triggered_buffer_cleanup(indio_dev); 1639ae6d9ce0SMartin Fuzzey 1640ae6d9ce0SMartin Fuzzey trigger_cleanup: 1641ae6d9ce0SMartin Fuzzey mma8452_trigger_cleanup(indio_dev); 1642ae6d9ce0SMartin Fuzzey 1643c7eeea93SPeter Meerwald return ret; 1644c7eeea93SPeter Meerwald } 1645c7eeea93SPeter Meerwald 1646c7eeea93SPeter Meerwald static int mma8452_remove(struct i2c_client *client) 1647c7eeea93SPeter Meerwald { 1648c7eeea93SPeter Meerwald struct iio_dev *indio_dev = i2c_get_clientdata(client); 1649c7eeea93SPeter Meerwald 1650c7eeea93SPeter Meerwald iio_device_unregister(indio_dev); 165196c0cb2bSMartin Kepplinger 165296c0cb2bSMartin Kepplinger pm_runtime_disable(&client->dev); 165396c0cb2bSMartin Kepplinger pm_runtime_set_suspended(&client->dev); 165496c0cb2bSMartin Kepplinger pm_runtime_put_noidle(&client->dev); 165596c0cb2bSMartin Kepplinger 1656c7eeea93SPeter Meerwald iio_triggered_buffer_cleanup(indio_dev); 1657ae6d9ce0SMartin Fuzzey mma8452_trigger_cleanup(indio_dev); 1658c7eeea93SPeter Meerwald mma8452_standby(iio_priv(indio_dev)); 1659c7eeea93SPeter Meerwald 1660c7eeea93SPeter Meerwald return 0; 1661c7eeea93SPeter Meerwald } 1662c7eeea93SPeter Meerwald 166396c0cb2bSMartin Kepplinger #ifdef CONFIG_PM 166496c0cb2bSMartin Kepplinger static int mma8452_runtime_suspend(struct device *dev) 166596c0cb2bSMartin Kepplinger { 166696c0cb2bSMartin Kepplinger struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 166796c0cb2bSMartin Kepplinger struct mma8452_data *data = iio_priv(indio_dev); 166896c0cb2bSMartin Kepplinger int ret; 166996c0cb2bSMartin Kepplinger 167096c0cb2bSMartin Kepplinger mutex_lock(&data->lock); 167196c0cb2bSMartin Kepplinger ret = mma8452_standby(data); 167296c0cb2bSMartin Kepplinger mutex_unlock(&data->lock); 167396c0cb2bSMartin Kepplinger if (ret < 0) { 167496c0cb2bSMartin Kepplinger dev_err(&data->client->dev, "powering off device failed\n"); 167596c0cb2bSMartin Kepplinger return -EAGAIN; 167696c0cb2bSMartin Kepplinger } 167796c0cb2bSMartin Kepplinger 167896c0cb2bSMartin Kepplinger return 0; 167996c0cb2bSMartin Kepplinger } 168096c0cb2bSMartin Kepplinger 168196c0cb2bSMartin Kepplinger static int mma8452_runtime_resume(struct device *dev) 168296c0cb2bSMartin Kepplinger { 168396c0cb2bSMartin Kepplinger struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 168496c0cb2bSMartin Kepplinger struct mma8452_data *data = iio_priv(indio_dev); 168596c0cb2bSMartin Kepplinger int ret, sleep_val; 168696c0cb2bSMartin Kepplinger 168796c0cb2bSMartin Kepplinger ret = mma8452_active(data); 168896c0cb2bSMartin Kepplinger if (ret < 0) 168996c0cb2bSMartin Kepplinger return ret; 169096c0cb2bSMartin Kepplinger 169196c0cb2bSMartin Kepplinger ret = mma8452_get_odr_index(data); 169296c0cb2bSMartin Kepplinger sleep_val = 1000 / mma8452_samp_freq[ret][0]; 169396c0cb2bSMartin Kepplinger if (sleep_val < 20) 169496c0cb2bSMartin Kepplinger usleep_range(sleep_val * 1000, 20000); 169596c0cb2bSMartin Kepplinger else 169696c0cb2bSMartin Kepplinger msleep_interruptible(sleep_val); 169796c0cb2bSMartin Kepplinger 169896c0cb2bSMartin Kepplinger return 0; 169996c0cb2bSMartin Kepplinger } 170096c0cb2bSMartin Kepplinger #endif 170196c0cb2bSMartin Kepplinger 1702c7eeea93SPeter Meerwald #ifdef CONFIG_PM_SLEEP 1703c7eeea93SPeter Meerwald static int mma8452_suspend(struct device *dev) 1704c7eeea93SPeter Meerwald { 1705c7eeea93SPeter Meerwald return mma8452_standby(iio_priv(i2c_get_clientdata( 1706c7eeea93SPeter Meerwald to_i2c_client(dev)))); 1707c7eeea93SPeter Meerwald } 1708c7eeea93SPeter Meerwald 1709c7eeea93SPeter Meerwald static int mma8452_resume(struct device *dev) 1710c7eeea93SPeter Meerwald { 1711c7eeea93SPeter Meerwald return mma8452_active(iio_priv(i2c_get_clientdata( 1712c7eeea93SPeter Meerwald to_i2c_client(dev)))); 1713c7eeea93SPeter Meerwald } 1714c7eeea93SPeter Meerwald #endif 1715c7eeea93SPeter Meerwald 171696c0cb2bSMartin Kepplinger static const struct dev_pm_ops mma8452_pm_ops = { 171796c0cb2bSMartin Kepplinger SET_SYSTEM_SLEEP_PM_OPS(mma8452_suspend, mma8452_resume) 171896c0cb2bSMartin Kepplinger SET_RUNTIME_PM_OPS(mma8452_runtime_suspend, 171996c0cb2bSMartin Kepplinger mma8452_runtime_resume, NULL) 172096c0cb2bSMartin Kepplinger }; 172196c0cb2bSMartin Kepplinger 1722c7eeea93SPeter Meerwald static const struct i2c_device_id mma8452_id[] = { 1723ddb851afSMartin Kepplinger { "mma8451", mma8451 }, 1724c3cdd6e4SMartin Kepplinger { "mma8452", mma8452 }, 1725c5ea1b58SMartin Kepplinger { "mma8453", mma8453 }, 1726417e008bSMartin Kepplinger { "mma8652", mma8652 }, 1727417e008bSMartin Kepplinger { "mma8653", mma8653 }, 1728e8731180SMartin Kepplinger { "fxls8471", fxls8471 }, 1729c7eeea93SPeter Meerwald { } 1730c7eeea93SPeter Meerwald }; 1731c7eeea93SPeter Meerwald MODULE_DEVICE_TABLE(i2c, mma8452_id); 1732c7eeea93SPeter Meerwald 1733c7eeea93SPeter Meerwald static struct i2c_driver mma8452_driver = { 1734c7eeea93SPeter Meerwald .driver = { 1735c7eeea93SPeter Meerwald .name = "mma8452", 1736a3fb96a8SMartin Fuzzey .of_match_table = of_match_ptr(mma8452_dt_ids), 173796c0cb2bSMartin Kepplinger .pm = &mma8452_pm_ops, 1738c7eeea93SPeter Meerwald }, 1739c7eeea93SPeter Meerwald .probe = mma8452_probe, 1740c7eeea93SPeter Meerwald .remove = mma8452_remove, 1741c7eeea93SPeter Meerwald .id_table = mma8452_id, 1742c7eeea93SPeter Meerwald }; 1743c7eeea93SPeter Meerwald module_i2c_driver(mma8452_driver); 1744c7eeea93SPeter Meerwald 1745c7eeea93SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 1746f26ab1aaSMartin Kepplinger MODULE_DESCRIPTION("Freescale / NXP MMA8452 accelerometer driver"); 1747c7eeea93SPeter Meerwald MODULE_LICENSE("GPL"); 1748