180e3f010SMartin Kepplinger // SPDX-License-Identifier: GPL-2.0 2c7eeea93SPeter Meerwald /* 3f26ab1aaSMartin Kepplinger * mma8452.c - Support for following Freescale / NXP 3-axis accelerometers: 4c5ea1b58SMartin Kepplinger * 516df666aSMartin Kepplinger * device name digital output 7-bit I2C slave address (pin selectable) 616df666aSMartin Kepplinger * --------------------------------------------------------------------- 716df666aSMartin Kepplinger * MMA8451Q 14 bit 0x1c / 0x1d 816df666aSMartin Kepplinger * MMA8452Q 12 bit 0x1c / 0x1d 916df666aSMartin Kepplinger * MMA8453Q 10 bit 0x1c / 0x1d 1016df666aSMartin Kepplinger * MMA8652FC 12 bit 0x1d 1116df666aSMartin Kepplinger * MMA8653FC 10 bit 0x1d 1216df666aSMartin Kepplinger * FXLS8471Q 14 bit 0x1e / 0x1d / 0x1c / 0x1f 13c7eeea93SPeter Meerwald * 1440836bc3SMartin Kepplinger * Copyright 2015 Martin Kepplinger <martink@posteo.de> 15c7eeea93SPeter Meerwald * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net> 16c7eeea93SPeter Meerwald * 17c7eeea93SPeter Meerwald * 18bce59b60SMartin Kepplinger * TODO: orientation events 19c7eeea93SPeter Meerwald */ 20c7eeea93SPeter Meerwald 21c7eeea93SPeter Meerwald #include <linux/module.h> 22c7eeea93SPeter Meerwald #include <linux/i2c.h> 23c7eeea93SPeter Meerwald #include <linux/iio/iio.h> 24c7eeea93SPeter Meerwald #include <linux/iio/sysfs.h> 25c7eeea93SPeter Meerwald #include <linux/iio/buffer.h> 26ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger.h> 27ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger_consumer.h> 28c7eeea93SPeter Meerwald #include <linux/iio/triggered_buffer.h> 2928e34278SMartin Fuzzey #include <linux/iio/events.h> 30c7eeea93SPeter Meerwald #include <linux/delay.h> 31c3cdd6e4SMartin Kepplinger #include <linux/of_device.h> 32d2a3e093SMartin Kepplinger #include <linux/of_irq.h> 3396c0cb2bSMartin Kepplinger #include <linux/pm_runtime.h> 34f6ff49b8SAnson Huang #include <linux/regulator/consumer.h> 35c7eeea93SPeter Meerwald 36c7eeea93SPeter Meerwald #define MMA8452_STATUS 0x00 3769abff81SHartmut Knaack #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) 38c5ea1b58SMartin Kepplinger #define MMA8452_OUT_X 0x01 /* MSB first */ 39c7eeea93SPeter Meerwald #define MMA8452_OUT_Y 0x03 40c7eeea93SPeter Meerwald #define MMA8452_OUT_Z 0x05 4128e34278SMartin Fuzzey #define MMA8452_INT_SRC 0x0c 42c7eeea93SPeter Meerwald #define MMA8452_WHO_AM_I 0x0d 43c7eeea93SPeter Meerwald #define MMA8452_DATA_CFG 0x0e 4469abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0) 4569abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_2G 0 4669abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_4G 1 4769abff81SHartmut Knaack #define MMA8452_DATA_CFG_FS_8G 2 4869abff81SHartmut Knaack #define MMA8452_DATA_CFG_HPF_MASK BIT(4) 491e79841aSMartin Fuzzey #define MMA8452_HP_FILTER_CUTOFF 0x0f 5069abff81SHartmut Knaack #define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0) 5160f562e7SMartin Kepplinger #define MMA8452_FF_MT_CFG 0x15 5260f562e7SMartin Kepplinger #define MMA8452_FF_MT_CFG_OAE BIT(6) 5360f562e7SMartin Kepplinger #define MMA8452_FF_MT_CFG_ELE BIT(7) 5460f562e7SMartin Kepplinger #define MMA8452_FF_MT_SRC 0x16 5560f562e7SMartin Kepplinger #define MMA8452_FF_MT_SRC_XHE BIT(1) 5660f562e7SMartin Kepplinger #define MMA8452_FF_MT_SRC_YHE BIT(3) 5760f562e7SMartin Kepplinger #define MMA8452_FF_MT_SRC_ZHE BIT(5) 5860f562e7SMartin Kepplinger #define MMA8452_FF_MT_THS 0x17 5960f562e7SMartin Kepplinger #define MMA8452_FF_MT_THS_MASK 0x7f 6060f562e7SMartin Kepplinger #define MMA8452_FF_MT_COUNT 0x18 61605f72deSHarinath Nampally #define MMA8452_FF_MT_CHAN_SHIFT 3 6228e34278SMartin Fuzzey #define MMA8452_TRANSIENT_CFG 0x1d 63605f72deSHarinath Nampally #define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) 641e79841aSMartin Fuzzey #define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) 6569abff81SHartmut Knaack #define MMA8452_TRANSIENT_CFG_ELE BIT(4) 6628e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC 0x1e 6728e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) 6828e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) 6928e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) 7028e34278SMartin Fuzzey #define MMA8452_TRANSIENT_THS 0x1f 7169abff81SHartmut Knaack #define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0) 725dbbd19fSMartin Fuzzey #define MMA8452_TRANSIENT_COUNT 0x20 73605f72deSHarinath Nampally #define MMA8452_TRANSIENT_CHAN_SHIFT 1 74c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG1 0x2a 7569abff81SHartmut Knaack #define MMA8452_CTRL_ACTIVE BIT(0) 7669abff81SHartmut Knaack #define MMA8452_CTRL_DR_MASK GENMASK(5, 3) 7769abff81SHartmut Knaack #define MMA8452_CTRL_DR_SHIFT 3 7869abff81SHartmut Knaack #define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ 79c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG2 0x2b 80ecabae71SMartin Fuzzey #define MMA8452_CTRL_REG2_RST BIT(6) 81ed859fc1SMartin Kepplinger #define MMA8452_CTRL_REG2_MODS_SHIFT 3 82ed859fc1SMartin Kepplinger #define MMA8452_CTRL_REG2_MODS_MASK 0x1b 8328e34278SMartin Fuzzey #define MMA8452_CTRL_REG4 0x2d 8428e34278SMartin Fuzzey #define MMA8452_CTRL_REG5 0x2e 8569abff81SHartmut Knaack #define MMA8452_OFF_X 0x2f 8669abff81SHartmut Knaack #define MMA8452_OFF_Y 0x30 8769abff81SHartmut Knaack #define MMA8452_OFF_Z 0x31 88c7eeea93SPeter Meerwald 892a17698cSMartin Fuzzey #define MMA8452_MAX_REG 0x31 902a17698cSMartin Fuzzey 91ae6d9ce0SMartin Fuzzey #define MMA8452_INT_DRDY BIT(0) 9260f562e7SMartin Kepplinger #define MMA8452_INT_FF_MT BIT(2) 9328e34278SMartin Fuzzey #define MMA8452_INT_TRANS BIT(5) 9428e34278SMartin Fuzzey 95244a93f6SMartin Kepplinger #define MMA8451_DEVICE_ID 0x1a 96c7eeea93SPeter Meerwald #define MMA8452_DEVICE_ID 0x2a 97c5ea1b58SMartin Kepplinger #define MMA8453_DEVICE_ID 0x3a 98417e008bSMartin Kepplinger #define MMA8652_DEVICE_ID 0x4a 99417e008bSMartin Kepplinger #define MMA8653_DEVICE_ID 0x5a 100e8731180SMartin Kepplinger #define FXLS8471_DEVICE_ID 0x6a 101c7eeea93SPeter Meerwald 10296c0cb2bSMartin Kepplinger #define MMA8452_AUTO_SUSPEND_DELAY_MS 2000 10396c0cb2bSMartin Kepplinger 104c7eeea93SPeter Meerwald struct mma8452_data { 105c7eeea93SPeter Meerwald struct i2c_client *client; 106c7eeea93SPeter Meerwald struct mutex lock; 107c7eeea93SPeter Meerwald u8 ctrl_reg1; 108c7eeea93SPeter Meerwald u8 data_cfg; 109c3cdd6e4SMartin Kepplinger const struct mma_chip_info *chip_info; 110a45d1238SRichard Tresidder int sleep_val; 111f6ff49b8SAnson Huang struct regulator *vdd_reg; 112f6ff49b8SAnson Huang struct regulator *vddio_reg; 113c3cdd6e4SMartin Kepplinger }; 114c3cdd6e4SMartin Kepplinger 115c3cdd6e4SMartin Kepplinger /** 116605f72deSHarinath Nampally * struct mma8452_event_regs - chip specific data related to events 117c3cdd6e4SMartin Kepplinger * @ev_cfg: event config register address 118c3cdd6e4SMartin Kepplinger * @ev_cfg_ele: latch bit in event config register 119c3cdd6e4SMartin Kepplinger * @ev_cfg_chan_shift: number of the bit to enable events in X 120c3cdd6e4SMartin Kepplinger * direction; in event config register 121c3cdd6e4SMartin Kepplinger * @ev_src: event source register address 122c3cdd6e4SMartin Kepplinger * @ev_ths: event threshold register address 123c3cdd6e4SMartin Kepplinger * @ev_ths_mask: mask for the threshold value 124c3cdd6e4SMartin Kepplinger * @ev_count: event count (period) register address 125c3cdd6e4SMartin Kepplinger * 126c3cdd6e4SMartin Kepplinger * Since not all chips supported by the driver support comparing high pass 127c3cdd6e4SMartin Kepplinger * filtered data for events (interrupts), different interrupt sources are 128c3cdd6e4SMartin Kepplinger * used for different chips and the relevant registers are included here. 129c3cdd6e4SMartin Kepplinger */ 130605f72deSHarinath Nampally struct mma8452_event_regs { 131605f72deSHarinath Nampally u8 ev_cfg; 132605f72deSHarinath Nampally u8 ev_cfg_ele; 133605f72deSHarinath Nampally u8 ev_cfg_chan_shift; 134605f72deSHarinath Nampally u8 ev_src; 135605f72deSHarinath Nampally u8 ev_ths; 136605f72deSHarinath Nampally u8 ev_ths_mask; 137605f72deSHarinath Nampally u8 ev_count; 138605f72deSHarinath Nampally }; 139605f72deSHarinath Nampally 140a654c062SHarinath Nampally static const struct mma8452_event_regs ff_mt_ev_regs = { 141605f72deSHarinath Nampally .ev_cfg = MMA8452_FF_MT_CFG, 142605f72deSHarinath Nampally .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, 143605f72deSHarinath Nampally .ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT, 144605f72deSHarinath Nampally .ev_src = MMA8452_FF_MT_SRC, 145605f72deSHarinath Nampally .ev_ths = MMA8452_FF_MT_THS, 146605f72deSHarinath Nampally .ev_ths_mask = MMA8452_FF_MT_THS_MASK, 147605f72deSHarinath Nampally .ev_count = MMA8452_FF_MT_COUNT 148605f72deSHarinath Nampally }; 149605f72deSHarinath Nampally 150a654c062SHarinath Nampally static const struct mma8452_event_regs trans_ev_regs = { 151605f72deSHarinath Nampally .ev_cfg = MMA8452_TRANSIENT_CFG, 152605f72deSHarinath Nampally .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, 153605f72deSHarinath Nampally .ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT, 154605f72deSHarinath Nampally .ev_src = MMA8452_TRANSIENT_SRC, 155605f72deSHarinath Nampally .ev_ths = MMA8452_TRANSIENT_THS, 156605f72deSHarinath Nampally .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, 157605f72deSHarinath Nampally .ev_count = MMA8452_TRANSIENT_COUNT, 158605f72deSHarinath Nampally }; 159605f72deSHarinath Nampally 160605f72deSHarinath Nampally /** 161605f72deSHarinath Nampally * struct mma_chip_info - chip specific data 162605f72deSHarinath Nampally * @chip_id: WHO_AM_I register's value 163605f72deSHarinath Nampally * @channels: struct iio_chan_spec matching the device's 164605f72deSHarinath Nampally * capabilities 165605f72deSHarinath Nampally * @num_channels: number of channels 166605f72deSHarinath Nampally * @mma_scales: scale factors for converting register values 167605f72deSHarinath Nampally * to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers 168605f72deSHarinath Nampally * per mode: m/s^2 and micro m/s^2 169605f72deSHarinath Nampally * @all_events: all events supported by this chip 170605f72deSHarinath Nampally * @enabled_events: event flags enabled and handled by this driver 171605f72deSHarinath Nampally */ 172c3cdd6e4SMartin Kepplinger struct mma_chip_info { 173c3cdd6e4SMartin Kepplinger u8 chip_id; 174c3cdd6e4SMartin Kepplinger const struct iio_chan_spec *channels; 175c3cdd6e4SMartin Kepplinger int num_channels; 176c3cdd6e4SMartin Kepplinger const int mma_scales[3][2]; 177605f72deSHarinath Nampally int all_events; 178605f72deSHarinath Nampally int enabled_events; 179c7eeea93SPeter Meerwald }; 180c7eeea93SPeter Meerwald 181e60378c1SMartin Kepplinger enum { 182e60378c1SMartin Kepplinger idx_x, 183e60378c1SMartin Kepplinger idx_y, 184e60378c1SMartin Kepplinger idx_z, 185e60378c1SMartin Kepplinger idx_ts, 186e60378c1SMartin Kepplinger }; 187e60378c1SMartin Kepplinger 188c7eeea93SPeter Meerwald static int mma8452_drdy(struct mma8452_data *data) 189c7eeea93SPeter Meerwald { 190c7eeea93SPeter Meerwald int tries = 150; 191c7eeea93SPeter Meerwald 192c7eeea93SPeter Meerwald while (tries-- > 0) { 193c7eeea93SPeter Meerwald int ret = i2c_smbus_read_byte_data(data->client, 194c7eeea93SPeter Meerwald MMA8452_STATUS); 195c7eeea93SPeter Meerwald if (ret < 0) 196c7eeea93SPeter Meerwald return ret; 197c7eeea93SPeter Meerwald if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) 198c7eeea93SPeter Meerwald return 0; 199686027fbSHartmut Knaack 200a45d1238SRichard Tresidder if (data->sleep_val <= 20) 201a45d1238SRichard Tresidder usleep_range(data->sleep_val * 250, 202a45d1238SRichard Tresidder data->sleep_val * 500); 203a45d1238SRichard Tresidder else 204c7eeea93SPeter Meerwald msleep(20); 205c7eeea93SPeter Meerwald } 206c7eeea93SPeter Meerwald 207c7eeea93SPeter Meerwald dev_err(&data->client->dev, "data not ready\n"); 208686027fbSHartmut Knaack 209c7eeea93SPeter Meerwald return -EIO; 210c7eeea93SPeter Meerwald } 211c7eeea93SPeter Meerwald 21296c0cb2bSMartin Kepplinger static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on) 21396c0cb2bSMartin Kepplinger { 21496c0cb2bSMartin Kepplinger #ifdef CONFIG_PM 21596c0cb2bSMartin Kepplinger int ret; 21696c0cb2bSMartin Kepplinger 21796c0cb2bSMartin Kepplinger if (on) { 21896c0cb2bSMartin Kepplinger ret = pm_runtime_get_sync(&client->dev); 21996c0cb2bSMartin Kepplinger } else { 22096c0cb2bSMartin Kepplinger pm_runtime_mark_last_busy(&client->dev); 22196c0cb2bSMartin Kepplinger ret = pm_runtime_put_autosuspend(&client->dev); 22296c0cb2bSMartin Kepplinger } 22396c0cb2bSMartin Kepplinger 22496c0cb2bSMartin Kepplinger if (ret < 0) { 22596c0cb2bSMartin Kepplinger dev_err(&client->dev, 22696c0cb2bSMartin Kepplinger "failed to change power state to %d\n", on); 22796c0cb2bSMartin Kepplinger if (on) 22896c0cb2bSMartin Kepplinger pm_runtime_put_noidle(&client->dev); 22996c0cb2bSMartin Kepplinger 23096c0cb2bSMartin Kepplinger return ret; 23196c0cb2bSMartin Kepplinger } 23296c0cb2bSMartin Kepplinger #endif 23396c0cb2bSMartin Kepplinger 23496c0cb2bSMartin Kepplinger return 0; 23596c0cb2bSMartin Kepplinger } 23696c0cb2bSMartin Kepplinger 237c7eeea93SPeter Meerwald static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) 238c7eeea93SPeter Meerwald { 239c7eeea93SPeter Meerwald int ret = mma8452_drdy(data); 240686027fbSHartmut Knaack 241c7eeea93SPeter Meerwald if (ret < 0) 242c7eeea93SPeter Meerwald return ret; 243686027fbSHartmut Knaack 24496c0cb2bSMartin Kepplinger ret = mma8452_set_runtime_pm_state(data->client, true); 24596c0cb2bSMartin Kepplinger if (ret) 24696c0cb2bSMartin Kepplinger return ret; 24796c0cb2bSMartin Kepplinger 24896c0cb2bSMartin Kepplinger ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X, 249686027fbSHartmut Knaack 3 * sizeof(__be16), (u8 *)buf); 25096c0cb2bSMartin Kepplinger 25196c0cb2bSMartin Kepplinger ret = mma8452_set_runtime_pm_state(data->client, false); 25296c0cb2bSMartin Kepplinger 25396c0cb2bSMartin Kepplinger return ret; 254c7eeea93SPeter Meerwald } 255c7eeea93SPeter Meerwald 256686027fbSHartmut Knaack static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2], 257686027fbSHartmut Knaack int n) 258c7eeea93SPeter Meerwald { 259c7eeea93SPeter Meerwald size_t len = 0; 260c7eeea93SPeter Meerwald 261c7eeea93SPeter Meerwald while (n-- > 0) 262686027fbSHartmut Knaack len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", 263686027fbSHartmut Knaack vals[n][0], vals[n][1]); 264c7eeea93SPeter Meerwald 265c7eeea93SPeter Meerwald /* replace trailing space by newline */ 266c7eeea93SPeter Meerwald buf[len - 1] = '\n'; 267c7eeea93SPeter Meerwald 268c7eeea93SPeter Meerwald return len; 269c7eeea93SPeter Meerwald } 270c7eeea93SPeter Meerwald 271c7eeea93SPeter Meerwald static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n, 272c7eeea93SPeter Meerwald int val, int val2) 273c7eeea93SPeter Meerwald { 274c7eeea93SPeter Meerwald while (n-- > 0) 275c7eeea93SPeter Meerwald if (val == vals[n][0] && val2 == vals[n][1]) 276c7eeea93SPeter Meerwald return n; 277c7eeea93SPeter Meerwald 278c7eeea93SPeter Meerwald return -EINVAL; 279c7eeea93SPeter Meerwald } 280c7eeea93SPeter Meerwald 28132b28076SMartin Kepplinger static unsigned int mma8452_get_odr_index(struct mma8452_data *data) 2825dbbd19fSMartin Fuzzey { 2835dbbd19fSMartin Fuzzey return (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >> 2845dbbd19fSMartin Fuzzey MMA8452_CTRL_DR_SHIFT; 2855dbbd19fSMartin Fuzzey } 2865dbbd19fSMartin Fuzzey 287c7eeea93SPeter Meerwald static const int mma8452_samp_freq[8][2] = { 288c7eeea93SPeter Meerwald {800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000}, 289c7eeea93SPeter Meerwald {6, 250000}, {1, 560000} 290c7eeea93SPeter Meerwald }; 291c7eeea93SPeter Meerwald 292ed859fc1SMartin Kepplinger /* Datasheet table: step time "Relationship with the ODR" (sample frequency) */ 293cc54a660SHarinath Nampally static const unsigned int mma8452_time_step_us[4][8] = { 294ed859fc1SMartin Kepplinger { 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 }, /* normal */ 295ed859fc1SMartin Kepplinger { 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 }, /* l p l n */ 296ed859fc1SMartin Kepplinger { 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 }, /* high res*/ 297ed859fc1SMartin Kepplinger { 1250, 2500, 5000, 10000, 20000, 80000, 160000, 160000 } /* l p */ 2985dbbd19fSMartin Fuzzey }; 2995dbbd19fSMartin Fuzzey 300ed859fc1SMartin Kepplinger /* Datasheet table "High-Pass Filter Cutoff Options" */ 301ed859fc1SMartin Kepplinger static const int mma8452_hp_filter_cutoff[4][8][4][2] = { 302ed859fc1SMartin Kepplinger { /* normal */ 3031e79841aSMartin Fuzzey { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 800 Hz sample */ 3041e79841aSMartin Fuzzey { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 400 Hz sample */ 3051e79841aSMartin Fuzzey { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, /* 200 Hz sample */ 3061e79841aSMartin Fuzzey { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, /* 100 Hz sample */ 3071e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 50 Hz sample */ 3081e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 12.5 Hz sample */ 3091e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 6.25 Hz sample */ 3101e79841aSMartin Fuzzey { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} } /* 1.56 Hz sample */ 311ed859fc1SMartin Kepplinger }, 312ed859fc1SMartin Kepplinger { /* low noise low power */ 313ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 314ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 315ed859fc1SMartin Kepplinger { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, 316ed859fc1SMartin Kepplinger { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, 317ed859fc1SMartin Kepplinger { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, 318ed859fc1SMartin Kepplinger { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }, 319ed859fc1SMartin Kepplinger { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }, 320ed859fc1SMartin Kepplinger { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} } 321ed859fc1SMartin Kepplinger }, 322ed859fc1SMartin Kepplinger { /* high resolution */ 323ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 324ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 325ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 326ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 327ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 328ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 329ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 330ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} } 331ed859fc1SMartin Kepplinger }, 332ed859fc1SMartin Kepplinger { /* low power */ 333ed859fc1SMartin Kepplinger { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, 334ed859fc1SMartin Kepplinger { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, 335ed859fc1SMartin Kepplinger { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, 336ed859fc1SMartin Kepplinger { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, 337ed859fc1SMartin Kepplinger { {1, 0}, {0, 500000}, {0, 250000}, {0, 125000} }, 338ed859fc1SMartin Kepplinger { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }, 339ed859fc1SMartin Kepplinger { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }, 340ed859fc1SMartin Kepplinger { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} } 341ed859fc1SMartin Kepplinger } 3421e79841aSMartin Fuzzey }; 3431e79841aSMartin Fuzzey 344ed859fc1SMartin Kepplinger /* Datasheet table "MODS Oversampling modes averaging values at each ODR" */ 345ed859fc1SMartin Kepplinger static const u16 mma8452_os_ratio[4][8] = { 346ed859fc1SMartin Kepplinger /* 800 Hz, 400 Hz, ... , 1.56 Hz */ 347ed859fc1SMartin Kepplinger { 2, 4, 4, 4, 4, 16, 32, 128 }, /* normal */ 348ed859fc1SMartin Kepplinger { 2, 4, 4, 4, 4, 4, 8, 32 }, /* low power low noise */ 349ed859fc1SMartin Kepplinger { 2, 4, 8, 16, 32, 128, 256, 1024 }, /* high resolution */ 350ed859fc1SMartin Kepplinger { 2, 2, 2, 2, 2, 2, 4, 16 } /* low power */ 351ed859fc1SMartin Kepplinger }; 352ed859fc1SMartin Kepplinger 353ed859fc1SMartin Kepplinger static int mma8452_get_power_mode(struct mma8452_data *data) 354ed859fc1SMartin Kepplinger { 355ed859fc1SMartin Kepplinger int reg; 356ed859fc1SMartin Kepplinger 357ed859fc1SMartin Kepplinger reg = i2c_smbus_read_byte_data(data->client, 358ed859fc1SMartin Kepplinger MMA8452_CTRL_REG2); 359ed859fc1SMartin Kepplinger if (reg < 0) 360ed859fc1SMartin Kepplinger return reg; 361ed859fc1SMartin Kepplinger 362ed859fc1SMartin Kepplinger return ((reg & MMA8452_CTRL_REG2_MODS_MASK) >> 363ed859fc1SMartin Kepplinger MMA8452_CTRL_REG2_MODS_SHIFT); 364ed859fc1SMartin Kepplinger } 365ed859fc1SMartin Kepplinger 366c7eeea93SPeter Meerwald static ssize_t mma8452_show_samp_freq_avail(struct device *dev, 367686027fbSHartmut Knaack struct device_attribute *attr, 368686027fbSHartmut Knaack char *buf) 369c7eeea93SPeter Meerwald { 370c7eeea93SPeter Meerwald return mma8452_show_int_plus_micros(buf, mma8452_samp_freq, 371c7eeea93SPeter Meerwald ARRAY_SIZE(mma8452_samp_freq)); 372c7eeea93SPeter Meerwald } 373c7eeea93SPeter Meerwald 374c7eeea93SPeter Meerwald static ssize_t mma8452_show_scale_avail(struct device *dev, 375686027fbSHartmut Knaack struct device_attribute *attr, 376686027fbSHartmut Knaack char *buf) 377c7eeea93SPeter Meerwald { 378c3cdd6e4SMartin Kepplinger struct mma8452_data *data = iio_priv(i2c_get_clientdata( 379c3cdd6e4SMartin Kepplinger to_i2c_client(dev))); 380c3cdd6e4SMartin Kepplinger 381c3cdd6e4SMartin Kepplinger return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales, 382c3cdd6e4SMartin Kepplinger ARRAY_SIZE(data->chip_info->mma_scales)); 383c7eeea93SPeter Meerwald } 384c7eeea93SPeter Meerwald 3851e79841aSMartin Fuzzey static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, 3861e79841aSMartin Fuzzey struct device_attribute *attr, 3871e79841aSMartin Fuzzey char *buf) 3881e79841aSMartin Fuzzey { 3891e79841aSMartin Fuzzey struct iio_dev *indio_dev = dev_to_iio_dev(dev); 3901e79841aSMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 391ed859fc1SMartin Kepplinger int i, j; 3921e79841aSMartin Fuzzey 393ed859fc1SMartin Kepplinger i = mma8452_get_odr_index(data); 394ed859fc1SMartin Kepplinger j = mma8452_get_power_mode(data); 395ed859fc1SMartin Kepplinger if (j < 0) 396ed859fc1SMartin Kepplinger return j; 397ed859fc1SMartin Kepplinger 398ed859fc1SMartin Kepplinger return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[j][i], 399ed859fc1SMartin Kepplinger ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0])); 400ed859fc1SMartin Kepplinger } 401ed859fc1SMartin Kepplinger 402ed859fc1SMartin Kepplinger static ssize_t mma8452_show_os_ratio_avail(struct device *dev, 403ed859fc1SMartin Kepplinger struct device_attribute *attr, 404ed859fc1SMartin Kepplinger char *buf) 405ed859fc1SMartin Kepplinger { 406ed859fc1SMartin Kepplinger struct iio_dev *indio_dev = dev_to_iio_dev(dev); 407ed859fc1SMartin Kepplinger struct mma8452_data *data = iio_priv(indio_dev); 408ed859fc1SMartin Kepplinger int i = mma8452_get_odr_index(data); 409ed859fc1SMartin Kepplinger int j; 410ed859fc1SMartin Kepplinger u16 val = 0; 411ed859fc1SMartin Kepplinger size_t len = 0; 412ed859fc1SMartin Kepplinger 413ed859fc1SMartin Kepplinger for (j = 0; j < ARRAY_SIZE(mma8452_os_ratio); j++) { 414ed859fc1SMartin Kepplinger if (val == mma8452_os_ratio[j][i]) 415ed859fc1SMartin Kepplinger continue; 416ed859fc1SMartin Kepplinger 417ed859fc1SMartin Kepplinger val = mma8452_os_ratio[j][i]; 418ed859fc1SMartin Kepplinger 419ed859fc1SMartin Kepplinger len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val); 420ed859fc1SMartin Kepplinger } 421ed859fc1SMartin Kepplinger buf[len - 1] = '\n'; 422ed859fc1SMartin Kepplinger 423ed859fc1SMartin Kepplinger return len; 4241e79841aSMartin Fuzzey } 4251e79841aSMartin Fuzzey 426c7eeea93SPeter Meerwald static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); 427cd327b00SHarinath Nampally static IIO_DEVICE_ATTR(in_accel_scale_available, 0444, 428c7eeea93SPeter Meerwald mma8452_show_scale_avail, NULL, 0); 4291e79841aSMartin Fuzzey static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available, 430cd327b00SHarinath Nampally 0444, mma8452_show_hp_cutoff_avail, NULL, 0); 431cd327b00SHarinath Nampally static IIO_DEVICE_ATTR(in_accel_oversampling_ratio_available, 0444, 432ed859fc1SMartin Kepplinger mma8452_show_os_ratio_avail, NULL, 0); 433c7eeea93SPeter Meerwald 434c7eeea93SPeter Meerwald static int mma8452_get_samp_freq_index(struct mma8452_data *data, 435c7eeea93SPeter Meerwald int val, int val2) 436c7eeea93SPeter Meerwald { 437c7eeea93SPeter Meerwald return mma8452_get_int_plus_micros_index(mma8452_samp_freq, 438686027fbSHartmut Knaack ARRAY_SIZE(mma8452_samp_freq), 439686027fbSHartmut Knaack val, val2); 440c7eeea93SPeter Meerwald } 441c7eeea93SPeter Meerwald 442686027fbSHartmut Knaack static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) 443c7eeea93SPeter Meerwald { 444c3cdd6e4SMartin Kepplinger return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales, 445c3cdd6e4SMartin Kepplinger ARRAY_SIZE(data->chip_info->mma_scales), val, val2); 446c7eeea93SPeter Meerwald } 447c7eeea93SPeter Meerwald 4481e79841aSMartin Fuzzey static int mma8452_get_hp_filter_index(struct mma8452_data *data, 4491e79841aSMartin Fuzzey int val, int val2) 4501e79841aSMartin Fuzzey { 451ed859fc1SMartin Kepplinger int i, j; 4521e79841aSMartin Fuzzey 453ed859fc1SMartin Kepplinger i = mma8452_get_odr_index(data); 454ed859fc1SMartin Kepplinger j = mma8452_get_power_mode(data); 455ed859fc1SMartin Kepplinger if (j < 0) 456ed859fc1SMartin Kepplinger return j; 457ed859fc1SMartin Kepplinger 458ed859fc1SMartin Kepplinger return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[j][i], 459ed859fc1SMartin Kepplinger ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]), val, val2); 4601e79841aSMartin Fuzzey } 4611e79841aSMartin Fuzzey 4621e79841aSMartin Fuzzey static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz) 4631e79841aSMartin Fuzzey { 464ed859fc1SMartin Kepplinger int j, i, ret; 4651e79841aSMartin Fuzzey 4661e79841aSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); 4671e79841aSMartin Fuzzey if (ret < 0) 4681e79841aSMartin Fuzzey return ret; 4691e79841aSMartin Fuzzey 4701e79841aSMartin Fuzzey i = mma8452_get_odr_index(data); 471ed859fc1SMartin Kepplinger j = mma8452_get_power_mode(data); 472ed859fc1SMartin Kepplinger if (j < 0) 473ed859fc1SMartin Kepplinger return j; 474ed859fc1SMartin Kepplinger 4751e79841aSMartin Fuzzey ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK; 476ed859fc1SMartin Kepplinger *hz = mma8452_hp_filter_cutoff[j][i][ret][0]; 477ed859fc1SMartin Kepplinger *uHz = mma8452_hp_filter_cutoff[j][i][ret][1]; 4781e79841aSMartin Fuzzey 4791e79841aSMartin Fuzzey return 0; 4801e79841aSMartin Fuzzey } 4811e79841aSMartin Fuzzey 482c7eeea93SPeter Meerwald static int mma8452_read_raw(struct iio_dev *indio_dev, 483c7eeea93SPeter Meerwald struct iio_chan_spec const *chan, 484c7eeea93SPeter Meerwald int *val, int *val2, long mask) 485c7eeea93SPeter Meerwald { 486c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 487c7eeea93SPeter Meerwald __be16 buffer[3]; 488c7eeea93SPeter Meerwald int i, ret; 489c7eeea93SPeter Meerwald 490c7eeea93SPeter Meerwald switch (mask) { 491c7eeea93SPeter Meerwald case IIO_CHAN_INFO_RAW: 4924d9b0413SAlison Schofield ret = iio_device_claim_direct_mode(indio_dev); 4934d9b0413SAlison Schofield if (ret) 4944d9b0413SAlison Schofield return ret; 495c7eeea93SPeter Meerwald 496c7eeea93SPeter Meerwald mutex_lock(&data->lock); 497c7eeea93SPeter Meerwald ret = mma8452_read(data, buffer); 498c7eeea93SPeter Meerwald mutex_unlock(&data->lock); 4994d9b0413SAlison Schofield iio_device_release_direct_mode(indio_dev); 500c7eeea93SPeter Meerwald if (ret < 0) 501c7eeea93SPeter Meerwald return ret; 502686027fbSHartmut Knaack 503c3cdd6e4SMartin Kepplinger *val = sign_extend32(be16_to_cpu( 504c3cdd6e4SMartin Kepplinger buffer[chan->scan_index]) >> chan->scan_type.shift, 505c3cdd6e4SMartin Kepplinger chan->scan_type.realbits - 1); 506686027fbSHartmut Knaack 507c7eeea93SPeter Meerwald return IIO_VAL_INT; 508c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SCALE: 509c7eeea93SPeter Meerwald i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; 510c3cdd6e4SMartin Kepplinger *val = data->chip_info->mma_scales[i][0]; 511c3cdd6e4SMartin Kepplinger *val2 = data->chip_info->mma_scales[i][1]; 512686027fbSHartmut Knaack 513c7eeea93SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 514c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SAMP_FREQ: 5155dbbd19fSMartin Fuzzey i = mma8452_get_odr_index(data); 516c7eeea93SPeter Meerwald *val = mma8452_samp_freq[i][0]; 517c7eeea93SPeter Meerwald *val2 = mma8452_samp_freq[i][1]; 518686027fbSHartmut Knaack 519c7eeea93SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 520c7eeea93SPeter Meerwald case IIO_CHAN_INFO_CALIBBIAS: 521686027fbSHartmut Knaack ret = i2c_smbus_read_byte_data(data->client, 5228b8ff3a6SMartin Kepplinger MMA8452_OFF_X + 5238b8ff3a6SMartin Kepplinger chan->scan_index); 524c7eeea93SPeter Meerwald if (ret < 0) 525c7eeea93SPeter Meerwald return ret; 526686027fbSHartmut Knaack 527c7eeea93SPeter Meerwald *val = sign_extend32(ret, 7); 528686027fbSHartmut Knaack 529c7eeea93SPeter Meerwald return IIO_VAL_INT; 5301e79841aSMartin Fuzzey case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 5311e79841aSMartin Fuzzey if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) { 5321e79841aSMartin Fuzzey ret = mma8452_read_hp_filter(data, val, val2); 5331e79841aSMartin Fuzzey if (ret < 0) 5341e79841aSMartin Fuzzey return ret; 5351e79841aSMartin Fuzzey } else { 5361e79841aSMartin Fuzzey *val = 0; 5371e79841aSMartin Fuzzey *val2 = 0; 5381e79841aSMartin Fuzzey } 539686027fbSHartmut Knaack 5401e79841aSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 541ed859fc1SMartin Kepplinger case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 542ed859fc1SMartin Kepplinger ret = mma8452_get_power_mode(data); 543ed859fc1SMartin Kepplinger if (ret < 0) 544ed859fc1SMartin Kepplinger return ret; 545ed859fc1SMartin Kepplinger 546ed859fc1SMartin Kepplinger i = mma8452_get_odr_index(data); 547ed859fc1SMartin Kepplinger 548ed859fc1SMartin Kepplinger *val = mma8452_os_ratio[ret][i]; 549ed859fc1SMartin Kepplinger return IIO_VAL_INT; 550c7eeea93SPeter Meerwald } 551686027fbSHartmut Knaack 552c7eeea93SPeter Meerwald return -EINVAL; 553c7eeea93SPeter Meerwald } 554c7eeea93SPeter Meerwald 555a45d1238SRichard Tresidder static int mma8452_calculate_sleep(struct mma8452_data *data) 556a45d1238SRichard Tresidder { 557a45d1238SRichard Tresidder int ret, i = mma8452_get_odr_index(data); 558a45d1238SRichard Tresidder 559a45d1238SRichard Tresidder if (mma8452_samp_freq[i][0] > 0) 560a45d1238SRichard Tresidder ret = 1000 / mma8452_samp_freq[i][0]; 561a45d1238SRichard Tresidder else 562a45d1238SRichard Tresidder ret = 1000; 563a45d1238SRichard Tresidder 564a45d1238SRichard Tresidder return ret == 0 ? 1 : ret; 565a45d1238SRichard Tresidder } 566a45d1238SRichard Tresidder 567c7eeea93SPeter Meerwald static int mma8452_standby(struct mma8452_data *data) 568c7eeea93SPeter Meerwald { 569c7eeea93SPeter Meerwald return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, 570c7eeea93SPeter Meerwald data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); 571c7eeea93SPeter Meerwald } 572c7eeea93SPeter Meerwald 573c7eeea93SPeter Meerwald static int mma8452_active(struct mma8452_data *data) 574c7eeea93SPeter Meerwald { 575c7eeea93SPeter Meerwald return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, 576c7eeea93SPeter Meerwald data->ctrl_reg1); 577c7eeea93SPeter Meerwald } 578c7eeea93SPeter Meerwald 579e866853dSMartin Kepplinger /* returns >0 if active, 0 if in standby and <0 on error */ 580e866853dSMartin Kepplinger static int mma8452_is_active(struct mma8452_data *data) 581e866853dSMartin Kepplinger { 582e866853dSMartin Kepplinger int reg; 583e866853dSMartin Kepplinger 584e866853dSMartin Kepplinger reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG1); 585e866853dSMartin Kepplinger if (reg < 0) 586e866853dSMartin Kepplinger return reg; 587e866853dSMartin Kepplinger 588e866853dSMartin Kepplinger return reg & MMA8452_CTRL_ACTIVE; 589e866853dSMartin Kepplinger } 590e866853dSMartin Kepplinger 591c7eeea93SPeter Meerwald static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) 592c7eeea93SPeter Meerwald { 593c7eeea93SPeter Meerwald int ret; 594e866853dSMartin Kepplinger int is_active; 595c7eeea93SPeter Meerwald 596c7eeea93SPeter Meerwald mutex_lock(&data->lock); 597c7eeea93SPeter Meerwald 598e866853dSMartin Kepplinger is_active = mma8452_is_active(data); 599e866853dSMartin Kepplinger if (is_active < 0) { 600e866853dSMartin Kepplinger ret = is_active; 601e866853dSMartin Kepplinger goto fail; 602e866853dSMartin Kepplinger } 603e866853dSMartin Kepplinger 604c7eeea93SPeter Meerwald /* config can only be changed when in standby */ 605e866853dSMartin Kepplinger if (is_active > 0) { 606c7eeea93SPeter Meerwald ret = mma8452_standby(data); 607c7eeea93SPeter Meerwald if (ret < 0) 608c7eeea93SPeter Meerwald goto fail; 609e866853dSMartin Kepplinger } 610c7eeea93SPeter Meerwald 611c7eeea93SPeter Meerwald ret = i2c_smbus_write_byte_data(data->client, reg, val); 612c7eeea93SPeter Meerwald if (ret < 0) 613c7eeea93SPeter Meerwald goto fail; 614c7eeea93SPeter Meerwald 615e866853dSMartin Kepplinger if (is_active > 0) { 616c7eeea93SPeter Meerwald ret = mma8452_active(data); 617c7eeea93SPeter Meerwald if (ret < 0) 618c7eeea93SPeter Meerwald goto fail; 619e866853dSMartin Kepplinger } 620c7eeea93SPeter Meerwald 621c7eeea93SPeter Meerwald ret = 0; 622c7eeea93SPeter Meerwald fail: 623c7eeea93SPeter Meerwald mutex_unlock(&data->lock); 624686027fbSHartmut Knaack 625c7eeea93SPeter Meerwald return ret; 626c7eeea93SPeter Meerwald } 627c7eeea93SPeter Meerwald 628ed859fc1SMartin Kepplinger static int mma8452_set_power_mode(struct mma8452_data *data, u8 mode) 629ed859fc1SMartin Kepplinger { 630ed859fc1SMartin Kepplinger int reg; 631ed859fc1SMartin Kepplinger 632ed859fc1SMartin Kepplinger reg = i2c_smbus_read_byte_data(data->client, 633ed859fc1SMartin Kepplinger MMA8452_CTRL_REG2); 634ed859fc1SMartin Kepplinger if (reg < 0) 635ed859fc1SMartin Kepplinger return reg; 636ed859fc1SMartin Kepplinger 637ed859fc1SMartin Kepplinger reg &= ~MMA8452_CTRL_REG2_MODS_MASK; 638ed859fc1SMartin Kepplinger reg |= mode << MMA8452_CTRL_REG2_MODS_SHIFT; 639ed859fc1SMartin Kepplinger 640ed859fc1SMartin Kepplinger return mma8452_change_config(data, MMA8452_CTRL_REG2, reg); 641ed859fc1SMartin Kepplinger } 642ed859fc1SMartin Kepplinger 6438b8ff3a6SMartin Kepplinger /* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */ 6444b04266aSMartin Kepplinger static int mma8452_freefall_mode_enabled(struct mma8452_data *data) 6454b04266aSMartin Kepplinger { 6464b04266aSMartin Kepplinger int val; 6474b04266aSMartin Kepplinger 648605f72deSHarinath Nampally val = i2c_smbus_read_byte_data(data->client, MMA8452_FF_MT_CFG); 6494b04266aSMartin Kepplinger if (val < 0) 6504b04266aSMartin Kepplinger return val; 6514b04266aSMartin Kepplinger 6524b04266aSMartin Kepplinger return !(val & MMA8452_FF_MT_CFG_OAE); 6534b04266aSMartin Kepplinger } 6544b04266aSMartin Kepplinger 6554b04266aSMartin Kepplinger static int mma8452_set_freefall_mode(struct mma8452_data *data, bool state) 6564b04266aSMartin Kepplinger { 6574b04266aSMartin Kepplinger int val; 6584b04266aSMartin Kepplinger 6594b04266aSMartin Kepplinger if ((state && mma8452_freefall_mode_enabled(data)) || 6604b04266aSMartin Kepplinger (!state && !(mma8452_freefall_mode_enabled(data)))) 6614b04266aSMartin Kepplinger return 0; 6624b04266aSMartin Kepplinger 663605f72deSHarinath Nampally val = i2c_smbus_read_byte_data(data->client, MMA8452_FF_MT_CFG); 6644b04266aSMartin Kepplinger if (val < 0) 6654b04266aSMartin Kepplinger return val; 6664b04266aSMartin Kepplinger 6674b04266aSMartin Kepplinger if (state) { 668605f72deSHarinath Nampally val |= BIT(idx_x + MMA8452_FF_MT_CHAN_SHIFT); 669605f72deSHarinath Nampally val |= BIT(idx_y + MMA8452_FF_MT_CHAN_SHIFT); 670605f72deSHarinath Nampally val |= BIT(idx_z + MMA8452_FF_MT_CHAN_SHIFT); 6714b04266aSMartin Kepplinger val &= ~MMA8452_FF_MT_CFG_OAE; 6724b04266aSMartin Kepplinger } else { 673605f72deSHarinath Nampally val &= ~BIT(idx_x + MMA8452_FF_MT_CHAN_SHIFT); 674605f72deSHarinath Nampally val &= ~BIT(idx_y + MMA8452_FF_MT_CHAN_SHIFT); 675605f72deSHarinath Nampally val &= ~BIT(idx_z + MMA8452_FF_MT_CHAN_SHIFT); 6764b04266aSMartin Kepplinger val |= MMA8452_FF_MT_CFG_OAE; 6774b04266aSMartin Kepplinger } 6784b04266aSMartin Kepplinger 679605f72deSHarinath Nampally return mma8452_change_config(data, MMA8452_FF_MT_CFG, val); 6804b04266aSMartin Kepplinger } 6814b04266aSMartin Kepplinger 6821e79841aSMartin Fuzzey static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, 6831e79841aSMartin Fuzzey int val, int val2) 6841e79841aSMartin Fuzzey { 6851e79841aSMartin Fuzzey int i, reg; 6861e79841aSMartin Fuzzey 6871e79841aSMartin Fuzzey i = mma8452_get_hp_filter_index(data, val, val2); 6881e79841aSMartin Fuzzey if (i < 0) 689b9fddcdbSHartmut Knaack return i; 6901e79841aSMartin Fuzzey 6911e79841aSMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, 6921e79841aSMartin Fuzzey MMA8452_HP_FILTER_CUTOFF); 6931e79841aSMartin Fuzzey if (reg < 0) 6941e79841aSMartin Fuzzey return reg; 695686027fbSHartmut Knaack 6961e79841aSMartin Fuzzey reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK; 6971e79841aSMartin Fuzzey reg |= i; 6981e79841aSMartin Fuzzey 6991e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg); 7001e79841aSMartin Fuzzey } 7011e79841aSMartin Fuzzey 702c7eeea93SPeter Meerwald static int mma8452_write_raw(struct iio_dev *indio_dev, 703c7eeea93SPeter Meerwald struct iio_chan_spec const *chan, 704c7eeea93SPeter Meerwald int val, int val2, long mask) 705c7eeea93SPeter Meerwald { 706c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 7071e79841aSMartin Fuzzey int i, ret; 708c7eeea93SPeter Meerwald 70979de2ee4SJonathan Cameron ret = iio_device_claim_direct_mode(indio_dev); 71079de2ee4SJonathan Cameron if (ret) 71179de2ee4SJonathan Cameron return ret; 712c7eeea93SPeter Meerwald 713c7eeea93SPeter Meerwald switch (mask) { 714c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SAMP_FREQ: 715c7eeea93SPeter Meerwald i = mma8452_get_samp_freq_index(data, val, val2); 71679de2ee4SJonathan Cameron if (i < 0) { 71779de2ee4SJonathan Cameron ret = i; 71879de2ee4SJonathan Cameron break; 71979de2ee4SJonathan Cameron } 720c7eeea93SPeter Meerwald data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; 721c7eeea93SPeter Meerwald data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; 722686027fbSHartmut Knaack 723a45d1238SRichard Tresidder data->sleep_val = mma8452_calculate_sleep(data); 724a45d1238SRichard Tresidder 72579de2ee4SJonathan Cameron ret = mma8452_change_config(data, MMA8452_CTRL_REG1, 726c7eeea93SPeter Meerwald data->ctrl_reg1); 72779de2ee4SJonathan Cameron break; 728c7eeea93SPeter Meerwald case IIO_CHAN_INFO_SCALE: 729c7eeea93SPeter Meerwald i = mma8452_get_scale_index(data, val, val2); 73079de2ee4SJonathan Cameron if (i < 0) { 73179de2ee4SJonathan Cameron ret = i; 73279de2ee4SJonathan Cameron break; 73379de2ee4SJonathan Cameron } 734686027fbSHartmut Knaack 735c7eeea93SPeter Meerwald data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; 736c7eeea93SPeter Meerwald data->data_cfg |= i; 737686027fbSHartmut Knaack 73879de2ee4SJonathan Cameron ret = mma8452_change_config(data, MMA8452_DATA_CFG, 739c7eeea93SPeter Meerwald data->data_cfg); 74079de2ee4SJonathan Cameron break; 741c7eeea93SPeter Meerwald case IIO_CHAN_INFO_CALIBBIAS: 74279de2ee4SJonathan Cameron if (val < -128 || val > 127) { 74379de2ee4SJonathan Cameron ret = -EINVAL; 74479de2ee4SJonathan Cameron break; 74579de2ee4SJonathan Cameron } 746686027fbSHartmut Knaack 74779de2ee4SJonathan Cameron ret = mma8452_change_config(data, 748686027fbSHartmut Knaack MMA8452_OFF_X + chan->scan_index, 749686027fbSHartmut Knaack val); 75079de2ee4SJonathan Cameron break; 7511e79841aSMartin Fuzzey 7521e79841aSMartin Fuzzey case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 7531e79841aSMartin Fuzzey if (val == 0 && val2 == 0) { 7541e79841aSMartin Fuzzey data->data_cfg &= ~MMA8452_DATA_CFG_HPF_MASK; 7551e79841aSMartin Fuzzey } else { 7561e79841aSMartin Fuzzey data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK; 7571e79841aSMartin Fuzzey ret = mma8452_set_hp_filter_frequency(data, val, val2); 7581e79841aSMartin Fuzzey if (ret < 0) 75979de2ee4SJonathan Cameron break; 7601e79841aSMartin Fuzzey } 761686027fbSHartmut Knaack 76279de2ee4SJonathan Cameron ret = mma8452_change_config(data, MMA8452_DATA_CFG, 7631e79841aSMartin Fuzzey data->data_cfg); 76479de2ee4SJonathan Cameron break; 7651e79841aSMartin Fuzzey 766ed859fc1SMartin Kepplinger case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 767ed859fc1SMartin Kepplinger ret = mma8452_get_odr_index(data); 768ed859fc1SMartin Kepplinger 769ed859fc1SMartin Kepplinger for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) { 77079de2ee4SJonathan Cameron if (mma8452_os_ratio[i][ret] == val) { 77179de2ee4SJonathan Cameron ret = mma8452_set_power_mode(data, i); 77279de2ee4SJonathan Cameron break; 77379de2ee4SJonathan Cameron } 77479de2ee4SJonathan Cameron } 77579de2ee4SJonathan Cameron break; 77679de2ee4SJonathan Cameron default: 77779de2ee4SJonathan Cameron ret = -EINVAL; 77879de2ee4SJonathan Cameron break; 779ed859fc1SMartin Kepplinger } 780ed859fc1SMartin Kepplinger 78179de2ee4SJonathan Cameron iio_device_release_direct_mode(indio_dev); 78279de2ee4SJonathan Cameron return ret; 783c7eeea93SPeter Meerwald } 784c7eeea93SPeter Meerwald 785605f72deSHarinath Nampally static int mma8452_get_event_regs(struct mma8452_data *data, 786605f72deSHarinath Nampally const struct iio_chan_spec *chan, enum iio_event_direction dir, 787605f72deSHarinath Nampally const struct mma8452_event_regs **ev_reg) 788605f72deSHarinath Nampally { 789605f72deSHarinath Nampally if (!chan) 790605f72deSHarinath Nampally return -EINVAL; 791605f72deSHarinath Nampally 792605f72deSHarinath Nampally switch (chan->type) { 793605f72deSHarinath Nampally case IIO_ACCEL: 794605f72deSHarinath Nampally switch (dir) { 795605f72deSHarinath Nampally case IIO_EV_DIR_RISING: 796605f72deSHarinath Nampally if ((data->chip_info->all_events 797605f72deSHarinath Nampally & MMA8452_INT_TRANS) && 798605f72deSHarinath Nampally (data->chip_info->enabled_events 799605f72deSHarinath Nampally & MMA8452_INT_TRANS)) 800a654c062SHarinath Nampally *ev_reg = &trans_ev_regs; 801605f72deSHarinath Nampally else 802a654c062SHarinath Nampally *ev_reg = &ff_mt_ev_regs; 803605f72deSHarinath Nampally return 0; 804605f72deSHarinath Nampally case IIO_EV_DIR_FALLING: 805a654c062SHarinath Nampally *ev_reg = &ff_mt_ev_regs; 806605f72deSHarinath Nampally return 0; 807605f72deSHarinath Nampally default: 808605f72deSHarinath Nampally return -EINVAL; 809605f72deSHarinath Nampally } 810605f72deSHarinath Nampally default: 811605f72deSHarinath Nampally return -EINVAL; 812605f72deSHarinath Nampally } 813605f72deSHarinath Nampally } 814605f72deSHarinath Nampally 8154febd9f1SHarinath Nampally static int mma8452_read_event_value(struct iio_dev *indio_dev, 81628e34278SMartin Fuzzey const struct iio_chan_spec *chan, 81728e34278SMartin Fuzzey enum iio_event_type type, 81828e34278SMartin Fuzzey enum iio_event_direction dir, 81928e34278SMartin Fuzzey enum iio_event_info info, 82028e34278SMartin Fuzzey int *val, int *val2) 82128e34278SMartin Fuzzey { 82228e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 823ed859fc1SMartin Kepplinger int ret, us, power_mode; 824605f72deSHarinath Nampally const struct mma8452_event_regs *ev_regs; 825605f72deSHarinath Nampally 826605f72deSHarinath Nampally ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); 827605f72deSHarinath Nampally if (ret) 828605f72deSHarinath Nampally return ret; 82928e34278SMartin Fuzzey 8305dbbd19fSMartin Fuzzey switch (info) { 8315dbbd19fSMartin Fuzzey case IIO_EV_INFO_VALUE: 832605f72deSHarinath Nampally ret = i2c_smbus_read_byte_data(data->client, ev_regs->ev_ths); 83328e34278SMartin Fuzzey if (ret < 0) 83428e34278SMartin Fuzzey return ret; 83528e34278SMartin Fuzzey 836605f72deSHarinath Nampally *val = ret & ev_regs->ev_ths_mask; 837686027fbSHartmut Knaack 83828e34278SMartin Fuzzey return IIO_VAL_INT; 8395dbbd19fSMartin Fuzzey 8405dbbd19fSMartin Fuzzey case IIO_EV_INFO_PERIOD: 841605f72deSHarinath Nampally ret = i2c_smbus_read_byte_data(data->client, ev_regs->ev_count); 8425dbbd19fSMartin Fuzzey if (ret < 0) 8435dbbd19fSMartin Fuzzey return ret; 8445dbbd19fSMartin Fuzzey 845ed859fc1SMartin Kepplinger power_mode = mma8452_get_power_mode(data); 846ed859fc1SMartin Kepplinger if (power_mode < 0) 847ed859fc1SMartin Kepplinger return power_mode; 848ed859fc1SMartin Kepplinger 849cc54a660SHarinath Nampally us = ret * mma8452_time_step_us[power_mode][ 8505dbbd19fSMartin Fuzzey mma8452_get_odr_index(data)]; 8515dbbd19fSMartin Fuzzey *val = us / USEC_PER_SEC; 8525dbbd19fSMartin Fuzzey *val2 = us % USEC_PER_SEC; 853686027fbSHartmut Knaack 8545dbbd19fSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 8555dbbd19fSMartin Fuzzey 8561e79841aSMartin Fuzzey case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: 8571e79841aSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, 8581e79841aSMartin Fuzzey MMA8452_TRANSIENT_CFG); 8591e79841aSMartin Fuzzey if (ret < 0) 8601e79841aSMartin Fuzzey return ret; 8611e79841aSMartin Fuzzey 8621e79841aSMartin Fuzzey if (ret & MMA8452_TRANSIENT_CFG_HPF_BYP) { 8631e79841aSMartin Fuzzey *val = 0; 8641e79841aSMartin Fuzzey *val2 = 0; 8651e79841aSMartin Fuzzey } else { 8661e79841aSMartin Fuzzey ret = mma8452_read_hp_filter(data, val, val2); 8671e79841aSMartin Fuzzey if (ret < 0) 8681e79841aSMartin Fuzzey return ret; 8691e79841aSMartin Fuzzey } 870686027fbSHartmut Knaack 8711e79841aSMartin Fuzzey return IIO_VAL_INT_PLUS_MICRO; 8721e79841aSMartin Fuzzey 8735dbbd19fSMartin Fuzzey default: 8745dbbd19fSMartin Fuzzey return -EINVAL; 8755dbbd19fSMartin Fuzzey } 87628e34278SMartin Fuzzey } 87728e34278SMartin Fuzzey 8784febd9f1SHarinath Nampally static int mma8452_write_event_value(struct iio_dev *indio_dev, 87928e34278SMartin Fuzzey const struct iio_chan_spec *chan, 88028e34278SMartin Fuzzey enum iio_event_type type, 88128e34278SMartin Fuzzey enum iio_event_direction dir, 88228e34278SMartin Fuzzey enum iio_event_info info, 88328e34278SMartin Fuzzey int val, int val2) 88428e34278SMartin Fuzzey { 88528e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 8861e79841aSMartin Fuzzey int ret, reg, steps; 887605f72deSHarinath Nampally const struct mma8452_event_regs *ev_regs; 888605f72deSHarinath Nampally 889605f72deSHarinath Nampally ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); 890605f72deSHarinath Nampally if (ret) 891605f72deSHarinath Nampally return ret; 89228e34278SMartin Fuzzey 8935dbbd19fSMartin Fuzzey switch (info) { 8945dbbd19fSMartin Fuzzey case IIO_EV_INFO_VALUE: 895605f72deSHarinath Nampally if (val < 0 || val > ev_regs->ev_ths_mask) 89611218226SHartmut Knaack return -EINVAL; 89711218226SHartmut Knaack 898605f72deSHarinath Nampally return mma8452_change_config(data, ev_regs->ev_ths, val); 8995dbbd19fSMartin Fuzzey 9005dbbd19fSMartin Fuzzey case IIO_EV_INFO_PERIOD: 901ed859fc1SMartin Kepplinger ret = mma8452_get_power_mode(data); 902ed859fc1SMartin Kepplinger if (ret < 0) 903ed859fc1SMartin Kepplinger return ret; 904ed859fc1SMartin Kepplinger 9055dbbd19fSMartin Fuzzey steps = (val * USEC_PER_SEC + val2) / 906cc54a660SHarinath Nampally mma8452_time_step_us[ret][ 9075dbbd19fSMartin Fuzzey mma8452_get_odr_index(data)]; 9085dbbd19fSMartin Fuzzey 90911218226SHartmut Knaack if (steps < 0 || steps > 0xff) 9105dbbd19fSMartin Fuzzey return -EINVAL; 9115dbbd19fSMartin Fuzzey 912605f72deSHarinath Nampally return mma8452_change_config(data, ev_regs->ev_count, steps); 913686027fbSHartmut Knaack 9141e79841aSMartin Fuzzey case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: 9151e79841aSMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, 9161e79841aSMartin Fuzzey MMA8452_TRANSIENT_CFG); 9171e79841aSMartin Fuzzey if (reg < 0) 9181e79841aSMartin Fuzzey return reg; 9191e79841aSMartin Fuzzey 9201e79841aSMartin Fuzzey if (val == 0 && val2 == 0) { 9211e79841aSMartin Fuzzey reg |= MMA8452_TRANSIENT_CFG_HPF_BYP; 9221e79841aSMartin Fuzzey } else { 9231e79841aSMartin Fuzzey reg &= ~MMA8452_TRANSIENT_CFG_HPF_BYP; 9241e79841aSMartin Fuzzey ret = mma8452_set_hp_filter_frequency(data, val, val2); 9251e79841aSMartin Fuzzey if (ret < 0) 9261e79841aSMartin Fuzzey return ret; 9271e79841aSMartin Fuzzey } 928686027fbSHartmut Knaack 9291e79841aSMartin Fuzzey return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg); 9301e79841aSMartin Fuzzey 9315dbbd19fSMartin Fuzzey default: 9325dbbd19fSMartin Fuzzey return -EINVAL; 9335dbbd19fSMartin Fuzzey } 93428e34278SMartin Fuzzey } 93528e34278SMartin Fuzzey 93628e34278SMartin Fuzzey static int mma8452_read_event_config(struct iio_dev *indio_dev, 93728e34278SMartin Fuzzey const struct iio_chan_spec *chan, 93828e34278SMartin Fuzzey enum iio_event_type type, 93928e34278SMartin Fuzzey enum iio_event_direction dir) 94028e34278SMartin Fuzzey { 94128e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 94228e34278SMartin Fuzzey int ret; 943605f72deSHarinath Nampally const struct mma8452_event_regs *ev_regs; 944605f72deSHarinath Nampally 945605f72deSHarinath Nampally ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); 946605f72deSHarinath Nampally if (ret) 947605f72deSHarinath Nampally return ret; 94828e34278SMartin Fuzzey 9494b04266aSMartin Kepplinger switch (dir) { 9504b04266aSMartin Kepplinger case IIO_EV_DIR_FALLING: 9514b04266aSMartin Kepplinger return mma8452_freefall_mode_enabled(data); 9524b04266aSMartin Kepplinger case IIO_EV_DIR_RISING: 953c3cdd6e4SMartin Kepplinger ret = i2c_smbus_read_byte_data(data->client, 954605f72deSHarinath Nampally ev_regs->ev_cfg); 95528e34278SMartin Fuzzey if (ret < 0) 95628e34278SMartin Fuzzey return ret; 95728e34278SMartin Fuzzey 9588b8ff3a6SMartin Kepplinger return !!(ret & BIT(chan->scan_index + 959605f72deSHarinath Nampally ev_regs->ev_cfg_chan_shift)); 9604b04266aSMartin Kepplinger default: 9614b04266aSMartin Kepplinger return -EINVAL; 9624b04266aSMartin Kepplinger } 96328e34278SMartin Fuzzey } 96428e34278SMartin Fuzzey 96528e34278SMartin Fuzzey static int mma8452_write_event_config(struct iio_dev *indio_dev, 96628e34278SMartin Fuzzey const struct iio_chan_spec *chan, 96728e34278SMartin Fuzzey enum iio_event_type type, 96828e34278SMartin Fuzzey enum iio_event_direction dir, 96928e34278SMartin Fuzzey int state) 97028e34278SMartin Fuzzey { 97128e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 97296c0cb2bSMartin Kepplinger int val, ret; 973605f72deSHarinath Nampally const struct mma8452_event_regs *ev_regs; 974605f72deSHarinath Nampally 975605f72deSHarinath Nampally ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); 976605f72deSHarinath Nampally if (ret) 977605f72deSHarinath Nampally return ret; 97896c0cb2bSMartin Kepplinger 97996c0cb2bSMartin Kepplinger ret = mma8452_set_runtime_pm_state(data->client, state); 98096c0cb2bSMartin Kepplinger if (ret) 98196c0cb2bSMartin Kepplinger return ret; 98228e34278SMartin Fuzzey 9834b04266aSMartin Kepplinger switch (dir) { 9844b04266aSMartin Kepplinger case IIO_EV_DIR_FALLING: 9854b04266aSMartin Kepplinger return mma8452_set_freefall_mode(data, state); 9864b04266aSMartin Kepplinger case IIO_EV_DIR_RISING: 987605f72deSHarinath Nampally val = i2c_smbus_read_byte_data(data->client, ev_regs->ev_cfg); 98828e34278SMartin Fuzzey if (val < 0) 98928e34278SMartin Fuzzey return val; 99028e34278SMartin Fuzzey 9914b04266aSMartin Kepplinger if (state) { 9924b04266aSMartin Kepplinger if (mma8452_freefall_mode_enabled(data)) { 993605f72deSHarinath Nampally val &= ~BIT(idx_x + ev_regs->ev_cfg_chan_shift); 994605f72deSHarinath Nampally val &= ~BIT(idx_y + ev_regs->ev_cfg_chan_shift); 995605f72deSHarinath Nampally val &= ~BIT(idx_z + ev_regs->ev_cfg_chan_shift); 9964b04266aSMartin Kepplinger val |= MMA8452_FF_MT_CFG_OAE; 9974b04266aSMartin Kepplinger } 998605f72deSHarinath Nampally val |= BIT(chan->scan_index + 999605f72deSHarinath Nampally ev_regs->ev_cfg_chan_shift); 10004b04266aSMartin Kepplinger } else { 10014b04266aSMartin Kepplinger if (mma8452_freefall_mode_enabled(data)) 10024b04266aSMartin Kepplinger return 0; 10034b04266aSMartin Kepplinger 1004605f72deSHarinath Nampally val &= ~BIT(chan->scan_index + 1005605f72deSHarinath Nampally ev_regs->ev_cfg_chan_shift); 10064b04266aSMartin Kepplinger } 100728e34278SMartin Fuzzey 1008605f72deSHarinath Nampally val |= ev_regs->ev_cfg_ele; 100928e34278SMartin Fuzzey 1010605f72deSHarinath Nampally return mma8452_change_config(data, ev_regs->ev_cfg, val); 10114b04266aSMartin Kepplinger default: 10124b04266aSMartin Kepplinger return -EINVAL; 10134b04266aSMartin Kepplinger } 101428e34278SMartin Fuzzey } 101528e34278SMartin Fuzzey 101628e34278SMartin Fuzzey static void mma8452_transient_interrupt(struct iio_dev *indio_dev) 101728e34278SMartin Fuzzey { 101828e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 1019bc2b7dabSGregor Boirie s64 ts = iio_get_time_ns(indio_dev); 102028e34278SMartin Fuzzey int src; 102128e34278SMartin Fuzzey 1022605f72deSHarinath Nampally src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC); 102328e34278SMartin Fuzzey if (src < 0) 102428e34278SMartin Fuzzey return; 102528e34278SMartin Fuzzey 1026605f72deSHarinath Nampally if (src & MMA8452_TRANSIENT_SRC_XTRANSE) 102728e34278SMartin Fuzzey iio_push_event(indio_dev, 102828e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, 1029c5d0db06SMartin Kepplinger IIO_EV_TYPE_MAG, 103028e34278SMartin Fuzzey IIO_EV_DIR_RISING), 103128e34278SMartin Fuzzey ts); 103228e34278SMartin Fuzzey 1033605f72deSHarinath Nampally if (src & MMA8452_TRANSIENT_SRC_YTRANSE) 103428e34278SMartin Fuzzey iio_push_event(indio_dev, 103528e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y, 1036c5d0db06SMartin Kepplinger IIO_EV_TYPE_MAG, 103728e34278SMartin Fuzzey IIO_EV_DIR_RISING), 103828e34278SMartin Fuzzey ts); 103928e34278SMartin Fuzzey 1040605f72deSHarinath Nampally if (src & MMA8452_TRANSIENT_SRC_ZTRANSE) 104128e34278SMartin Fuzzey iio_push_event(indio_dev, 104228e34278SMartin Fuzzey IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z, 1043c5d0db06SMartin Kepplinger IIO_EV_TYPE_MAG, 104428e34278SMartin Fuzzey IIO_EV_DIR_RISING), 104528e34278SMartin Fuzzey ts); 104628e34278SMartin Fuzzey } 104728e34278SMartin Fuzzey 104828e34278SMartin Fuzzey static irqreturn_t mma8452_interrupt(int irq, void *p) 104928e34278SMartin Fuzzey { 105028e34278SMartin Fuzzey struct iio_dev *indio_dev = p; 105128e34278SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 1052ae6d9ce0SMartin Fuzzey int ret = IRQ_NONE; 105328e34278SMartin Fuzzey int src; 105428e34278SMartin Fuzzey 105528e34278SMartin Fuzzey src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC); 105628e34278SMartin Fuzzey if (src < 0) 105728e34278SMartin Fuzzey return IRQ_NONE; 105828e34278SMartin Fuzzey 1059b02ec67aSLeonard Crestez if (!(src & (data->chip_info->enabled_events | MMA8452_INT_DRDY))) 1060605f72deSHarinath Nampally return IRQ_NONE; 1061605f72deSHarinath Nampally 1062ae6d9ce0SMartin Fuzzey if (src & MMA8452_INT_DRDY) { 1063ae6d9ce0SMartin Fuzzey iio_trigger_poll_chained(indio_dev->trig); 1064ae6d9ce0SMartin Fuzzey ret = IRQ_HANDLED; 106528e34278SMartin Fuzzey } 106628e34278SMartin Fuzzey 1067605f72deSHarinath Nampally if (src & MMA8452_INT_FF_MT) { 1068605f72deSHarinath Nampally if (mma8452_freefall_mode_enabled(data)) { 1069605f72deSHarinath Nampally s64 ts = iio_get_time_ns(indio_dev); 1070605f72deSHarinath Nampally 1071605f72deSHarinath Nampally iio_push_event(indio_dev, 1072605f72deSHarinath Nampally IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, 1073605f72deSHarinath Nampally IIO_MOD_X_AND_Y_AND_Z, 1074605f72deSHarinath Nampally IIO_EV_TYPE_MAG, 1075605f72deSHarinath Nampally IIO_EV_DIR_FALLING), 1076605f72deSHarinath Nampally ts); 1077605f72deSHarinath Nampally } 1078605f72deSHarinath Nampally ret = IRQ_HANDLED; 1079605f72deSHarinath Nampally } 1080605f72deSHarinath Nampally 1081605f72deSHarinath Nampally if (src & MMA8452_INT_TRANS) { 1082ae6d9ce0SMartin Fuzzey mma8452_transient_interrupt(indio_dev); 1083ae6d9ce0SMartin Fuzzey ret = IRQ_HANDLED; 1084ae6d9ce0SMartin Fuzzey } 1085ae6d9ce0SMartin Fuzzey 1086ae6d9ce0SMartin Fuzzey return ret; 108728e34278SMartin Fuzzey } 108828e34278SMartin Fuzzey 1089c7eeea93SPeter Meerwald static irqreturn_t mma8452_trigger_handler(int irq, void *p) 1090c7eeea93SPeter Meerwald { 1091c7eeea93SPeter Meerwald struct iio_poll_func *pf = p; 1092c7eeea93SPeter Meerwald struct iio_dev *indio_dev = pf->indio_dev; 1093c7eeea93SPeter Meerwald struct mma8452_data *data = iio_priv(indio_dev); 1094c7eeea93SPeter Meerwald u8 buffer[16]; /* 3 16-bit channels + padding + ts */ 1095c7eeea93SPeter Meerwald int ret; 1096c7eeea93SPeter Meerwald 1097c7eeea93SPeter Meerwald ret = mma8452_read(data, (__be16 *)buffer); 1098c7eeea93SPeter Meerwald if (ret < 0) 1099c7eeea93SPeter Meerwald goto done; 1100c7eeea93SPeter Meerwald 1101c7eeea93SPeter Meerwald iio_push_to_buffers_with_timestamp(indio_dev, buffer, 1102bc2b7dabSGregor Boirie iio_get_time_ns(indio_dev)); 1103c7eeea93SPeter Meerwald 1104c7eeea93SPeter Meerwald done: 1105c7eeea93SPeter Meerwald iio_trigger_notify_done(indio_dev->trig); 1106686027fbSHartmut Knaack 1107c7eeea93SPeter Meerwald return IRQ_HANDLED; 1108c7eeea93SPeter Meerwald } 1109c7eeea93SPeter Meerwald 11102a17698cSMartin Fuzzey static int mma8452_reg_access_dbg(struct iio_dev *indio_dev, 1111f8b7b30fSHarinath Nampally unsigned int reg, unsigned int writeval, 1112f8b7b30fSHarinath Nampally unsigned int *readval) 11132a17698cSMartin Fuzzey { 11142a17698cSMartin Fuzzey int ret; 11152a17698cSMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 11162a17698cSMartin Fuzzey 11172a17698cSMartin Fuzzey if (reg > MMA8452_MAX_REG) 11182a17698cSMartin Fuzzey return -EINVAL; 11192a17698cSMartin Fuzzey 11202a17698cSMartin Fuzzey if (!readval) 11212a17698cSMartin Fuzzey return mma8452_change_config(data, reg, writeval); 11222a17698cSMartin Fuzzey 11232a17698cSMartin Fuzzey ret = i2c_smbus_read_byte_data(data->client, reg); 11242a17698cSMartin Fuzzey if (ret < 0) 11252a17698cSMartin Fuzzey return ret; 11262a17698cSMartin Fuzzey 11272a17698cSMartin Fuzzey *readval = ret; 11282a17698cSMartin Fuzzey 11292a17698cSMartin Fuzzey return 0; 11302a17698cSMartin Fuzzey } 11312a17698cSMartin Fuzzey 11324b04266aSMartin Kepplinger static const struct iio_event_spec mma8452_freefall_event[] = { 11334b04266aSMartin Kepplinger { 11344b04266aSMartin Kepplinger .type = IIO_EV_TYPE_MAG, 11354b04266aSMartin Kepplinger .dir = IIO_EV_DIR_FALLING, 11364b04266aSMartin Kepplinger .mask_separate = BIT(IIO_EV_INFO_ENABLE), 11374b04266aSMartin Kepplinger .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 11384b04266aSMartin Kepplinger BIT(IIO_EV_INFO_PERIOD) | 11394b04266aSMartin Kepplinger BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB) 11404b04266aSMartin Kepplinger }, 11414b04266aSMartin Kepplinger }; 11424b04266aSMartin Kepplinger 11434b04266aSMartin Kepplinger static const struct iio_event_spec mma8652_freefall_event[] = { 11444b04266aSMartin Kepplinger { 11454b04266aSMartin Kepplinger .type = IIO_EV_TYPE_MAG, 11464b04266aSMartin Kepplinger .dir = IIO_EV_DIR_FALLING, 11474b04266aSMartin Kepplinger .mask_separate = BIT(IIO_EV_INFO_ENABLE), 11484b04266aSMartin Kepplinger .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 11494b04266aSMartin Kepplinger BIT(IIO_EV_INFO_PERIOD) 11504b04266aSMartin Kepplinger }, 11514b04266aSMartin Kepplinger }; 11524b04266aSMartin Kepplinger 115328e34278SMartin Fuzzey static const struct iio_event_spec mma8452_transient_event[] = { 115428e34278SMartin Fuzzey { 1155c5d0db06SMartin Kepplinger .type = IIO_EV_TYPE_MAG, 115628e34278SMartin Fuzzey .dir = IIO_EV_DIR_RISING, 115728e34278SMartin Fuzzey .mask_separate = BIT(IIO_EV_INFO_ENABLE), 11585dbbd19fSMartin Fuzzey .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 11591e79841aSMartin Fuzzey BIT(IIO_EV_INFO_PERIOD) | 11601e79841aSMartin Fuzzey BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB) 116128e34278SMartin Fuzzey }, 116228e34278SMartin Fuzzey }; 116328e34278SMartin Fuzzey 116460f562e7SMartin Kepplinger static const struct iio_event_spec mma8452_motion_event[] = { 116560f562e7SMartin Kepplinger { 116660f562e7SMartin Kepplinger .type = IIO_EV_TYPE_MAG, 116760f562e7SMartin Kepplinger .dir = IIO_EV_DIR_RISING, 116860f562e7SMartin Kepplinger .mask_separate = BIT(IIO_EV_INFO_ENABLE), 116960f562e7SMartin Kepplinger .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 117060f562e7SMartin Kepplinger BIT(IIO_EV_INFO_PERIOD) 117160f562e7SMartin Kepplinger }, 117260f562e7SMartin Kepplinger }; 117360f562e7SMartin Kepplinger 117428e34278SMartin Fuzzey /* 117528e34278SMartin Fuzzey * Threshold is configured in fixed 8G/127 steps regardless of 117628e34278SMartin Fuzzey * currently selected scale for measurement. 117728e34278SMartin Fuzzey */ 117828e34278SMartin Fuzzey static IIO_CONST_ATTR_NAMED(accel_transient_scale, in_accel_scale, "0.617742"); 117928e34278SMartin Fuzzey 118028e34278SMartin Fuzzey static struct attribute *mma8452_event_attributes[] = { 118128e34278SMartin Fuzzey &iio_const_attr_accel_transient_scale.dev_attr.attr, 118228e34278SMartin Fuzzey NULL, 118328e34278SMartin Fuzzey }; 118428e34278SMartin Fuzzey 118528e34278SMartin Fuzzey static struct attribute_group mma8452_event_attribute_group = { 118628e34278SMartin Fuzzey .attrs = mma8452_event_attributes, 118728e34278SMartin Fuzzey }; 118828e34278SMartin Fuzzey 11894b04266aSMartin Kepplinger #define MMA8452_FREEFALL_CHANNEL(modifier) { \ 11904b04266aSMartin Kepplinger .type = IIO_ACCEL, \ 11914b04266aSMartin Kepplinger .modified = 1, \ 11924b04266aSMartin Kepplinger .channel2 = modifier, \ 11934b04266aSMartin Kepplinger .scan_index = -1, \ 11944b04266aSMartin Kepplinger .event_spec = mma8452_freefall_event, \ 11954b04266aSMartin Kepplinger .num_event_specs = ARRAY_SIZE(mma8452_freefall_event), \ 11964b04266aSMartin Kepplinger } 11974b04266aSMartin Kepplinger 11984b04266aSMartin Kepplinger #define MMA8652_FREEFALL_CHANNEL(modifier) { \ 11994b04266aSMartin Kepplinger .type = IIO_ACCEL, \ 12004b04266aSMartin Kepplinger .modified = 1, \ 12014b04266aSMartin Kepplinger .channel2 = modifier, \ 12024b04266aSMartin Kepplinger .scan_index = -1, \ 12034b04266aSMartin Kepplinger .event_spec = mma8652_freefall_event, \ 12044b04266aSMartin Kepplinger .num_event_specs = ARRAY_SIZE(mma8652_freefall_event), \ 12054b04266aSMartin Kepplinger } 12064b04266aSMartin Kepplinger 1207c3cdd6e4SMartin Kepplinger #define MMA8452_CHANNEL(axis, idx, bits) { \ 1208c7eeea93SPeter Meerwald .type = IIO_ACCEL, \ 1209c7eeea93SPeter Meerwald .modified = 1, \ 1210c7eeea93SPeter Meerwald .channel2 = IIO_MOD_##axis, \ 1211c7eeea93SPeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 1212c7eeea93SPeter Meerwald BIT(IIO_CHAN_INFO_CALIBBIAS), \ 1213c7eeea93SPeter Meerwald .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 12141e79841aSMartin Fuzzey BIT(IIO_CHAN_INFO_SCALE) | \ 1215ed859fc1SMartin Kepplinger BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) | \ 1216ed859fc1SMartin Kepplinger BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ 1217c7eeea93SPeter Meerwald .scan_index = idx, \ 1218c7eeea93SPeter Meerwald .scan_type = { \ 1219c7eeea93SPeter Meerwald .sign = 's', \ 1220c3cdd6e4SMartin Kepplinger .realbits = (bits), \ 1221c7eeea93SPeter Meerwald .storagebits = 16, \ 1222c3cdd6e4SMartin Kepplinger .shift = 16 - (bits), \ 1223c7eeea93SPeter Meerwald .endianness = IIO_BE, \ 1224c7eeea93SPeter Meerwald }, \ 122528e34278SMartin Fuzzey .event_spec = mma8452_transient_event, \ 122628e34278SMartin Fuzzey .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \ 1227c7eeea93SPeter Meerwald } 1228c7eeea93SPeter Meerwald 1229417e008bSMartin Kepplinger #define MMA8652_CHANNEL(axis, idx, bits) { \ 1230417e008bSMartin Kepplinger .type = IIO_ACCEL, \ 1231417e008bSMartin Kepplinger .modified = 1, \ 1232417e008bSMartin Kepplinger .channel2 = IIO_MOD_##axis, \ 1233417e008bSMartin Kepplinger .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 1234417e008bSMartin Kepplinger BIT(IIO_CHAN_INFO_CALIBBIAS), \ 1235417e008bSMartin Kepplinger .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 1236ed859fc1SMartin Kepplinger BIT(IIO_CHAN_INFO_SCALE) | \ 1237ed859fc1SMartin Kepplinger BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ 1238417e008bSMartin Kepplinger .scan_index = idx, \ 1239417e008bSMartin Kepplinger .scan_type = { \ 1240417e008bSMartin Kepplinger .sign = 's', \ 1241417e008bSMartin Kepplinger .realbits = (bits), \ 1242417e008bSMartin Kepplinger .storagebits = 16, \ 1243417e008bSMartin Kepplinger .shift = 16 - (bits), \ 1244417e008bSMartin Kepplinger .endianness = IIO_BE, \ 1245417e008bSMartin Kepplinger }, \ 1246417e008bSMartin Kepplinger .event_spec = mma8452_motion_event, \ 1247417e008bSMartin Kepplinger .num_event_specs = ARRAY_SIZE(mma8452_motion_event), \ 1248417e008bSMartin Kepplinger } 1249417e008bSMartin Kepplinger 1250244a93f6SMartin Kepplinger static const struct iio_chan_spec mma8451_channels[] = { 1251244a93f6SMartin Kepplinger MMA8452_CHANNEL(X, idx_x, 14), 1252244a93f6SMartin Kepplinger MMA8452_CHANNEL(Y, idx_y, 14), 1253244a93f6SMartin Kepplinger MMA8452_CHANNEL(Z, idx_z, 14), 1254244a93f6SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 1255244a93f6SMartin Kepplinger MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1256244a93f6SMartin Kepplinger }; 1257244a93f6SMartin Kepplinger 1258c7eeea93SPeter Meerwald static const struct iio_chan_spec mma8452_channels[] = { 1259e60378c1SMartin Kepplinger MMA8452_CHANNEL(X, idx_x, 12), 1260e60378c1SMartin Kepplinger MMA8452_CHANNEL(Y, idx_y, 12), 1261e60378c1SMartin Kepplinger MMA8452_CHANNEL(Z, idx_z, 12), 1262e60378c1SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 12634b04266aSMartin Kepplinger MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1264c7eeea93SPeter Meerwald }; 1265c7eeea93SPeter Meerwald 1266c5ea1b58SMartin Kepplinger static const struct iio_chan_spec mma8453_channels[] = { 1267e60378c1SMartin Kepplinger MMA8452_CHANNEL(X, idx_x, 10), 1268e60378c1SMartin Kepplinger MMA8452_CHANNEL(Y, idx_y, 10), 1269e60378c1SMartin Kepplinger MMA8452_CHANNEL(Z, idx_z, 10), 1270e60378c1SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 12714b04266aSMartin Kepplinger MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1272c5ea1b58SMartin Kepplinger }; 1273c5ea1b58SMartin Kepplinger 1274417e008bSMartin Kepplinger static const struct iio_chan_spec mma8652_channels[] = { 1275e60378c1SMartin Kepplinger MMA8652_CHANNEL(X, idx_x, 12), 1276e60378c1SMartin Kepplinger MMA8652_CHANNEL(Y, idx_y, 12), 1277e60378c1SMartin Kepplinger MMA8652_CHANNEL(Z, idx_z, 12), 1278e60378c1SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 12794b04266aSMartin Kepplinger MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1280417e008bSMartin Kepplinger }; 1281417e008bSMartin Kepplinger 1282417e008bSMartin Kepplinger static const struct iio_chan_spec mma8653_channels[] = { 1283e60378c1SMartin Kepplinger MMA8652_CHANNEL(X, idx_x, 10), 1284e60378c1SMartin Kepplinger MMA8652_CHANNEL(Y, idx_y, 10), 1285e60378c1SMartin Kepplinger MMA8652_CHANNEL(Z, idx_z, 10), 1286e60378c1SMartin Kepplinger IIO_CHAN_SOFT_TIMESTAMP(idx_ts), 12874b04266aSMartin Kepplinger MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z), 1288417e008bSMartin Kepplinger }; 1289417e008bSMartin Kepplinger 1290c3cdd6e4SMartin Kepplinger enum { 1291244a93f6SMartin Kepplinger mma8451, 1292c3cdd6e4SMartin Kepplinger mma8452, 1293c5ea1b58SMartin Kepplinger mma8453, 1294417e008bSMartin Kepplinger mma8652, 1295417e008bSMartin Kepplinger mma8653, 1296e8731180SMartin Kepplinger fxls8471, 1297c3cdd6e4SMartin Kepplinger }; 1298c3cdd6e4SMartin Kepplinger 1299c3cdd6e4SMartin Kepplinger static const struct mma_chip_info mma_chip_info_table[] = { 1300244a93f6SMartin Kepplinger [mma8451] = { 1301244a93f6SMartin Kepplinger .chip_id = MMA8451_DEVICE_ID, 1302244a93f6SMartin Kepplinger .channels = mma8451_channels, 1303244a93f6SMartin Kepplinger .num_channels = ARRAY_SIZE(mma8451_channels), 1304c3cdd6e4SMartin Kepplinger /* 1305c3cdd6e4SMartin Kepplinger * Hardware has fullscale of -2G, -4G, -8G corresponding to 1306244a93f6SMartin Kepplinger * raw value -8192 for 14 bit, -2048 for 12 bit or -512 for 10 1307244a93f6SMartin Kepplinger * bit. 1308c3cdd6e4SMartin Kepplinger * The userspace interface uses m/s^2 and we declare micro units 1309c3cdd6e4SMartin Kepplinger * So scale factor for 12 bit here is given by: 1310c3cdd6e4SMartin Kepplinger * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 1311c3cdd6e4SMartin Kepplinger */ 1312244a93f6SMartin Kepplinger .mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} }, 1313605f72deSHarinath Nampally /* 1314605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1315605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1316605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1317605f72deSHarinath Nampally */ 1318605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1319605f72deSHarinath Nampally MMA8452_INT_TRANS | 1320605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1321605f72deSHarinath Nampally .enabled_events = MMA8452_INT_TRANS | 1322605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1323244a93f6SMartin Kepplinger }, 1324244a93f6SMartin Kepplinger [mma8452] = { 1325244a93f6SMartin Kepplinger .chip_id = MMA8452_DEVICE_ID, 1326244a93f6SMartin Kepplinger .channels = mma8452_channels, 1327244a93f6SMartin Kepplinger .num_channels = ARRAY_SIZE(mma8452_channels), 1328c3cdd6e4SMartin Kepplinger .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, 1329605f72deSHarinath Nampally /* 1330605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1331605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1332605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1333605f72deSHarinath Nampally */ 1334605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1335605f72deSHarinath Nampally MMA8452_INT_TRANS | 1336605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1337605f72deSHarinath Nampally .enabled_events = MMA8452_INT_TRANS | 1338605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1339c3cdd6e4SMartin Kepplinger }, 1340c5ea1b58SMartin Kepplinger [mma8453] = { 1341c5ea1b58SMartin Kepplinger .chip_id = MMA8453_DEVICE_ID, 1342c5ea1b58SMartin Kepplinger .channels = mma8453_channels, 1343c5ea1b58SMartin Kepplinger .num_channels = ARRAY_SIZE(mma8453_channels), 1344c5ea1b58SMartin Kepplinger .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, 1345605f72deSHarinath Nampally /* 1346605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1347605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1348605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1349605f72deSHarinath Nampally */ 1350605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1351605f72deSHarinath Nampally MMA8452_INT_TRANS | 1352605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1353605f72deSHarinath Nampally .enabled_events = MMA8452_INT_TRANS | 1354605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1355c5ea1b58SMartin Kepplinger }, 1356417e008bSMartin Kepplinger [mma8652] = { 1357417e008bSMartin Kepplinger .chip_id = MMA8652_DEVICE_ID, 1358417e008bSMartin Kepplinger .channels = mma8652_channels, 1359417e008bSMartin Kepplinger .num_channels = ARRAY_SIZE(mma8652_channels), 1360417e008bSMartin Kepplinger .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, 1361605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1362605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1363605f72deSHarinath Nampally .enabled_events = MMA8452_INT_FF_MT, 1364417e008bSMartin Kepplinger }, 1365417e008bSMartin Kepplinger [mma8653] = { 1366417e008bSMartin Kepplinger .chip_id = MMA8653_DEVICE_ID, 1367417e008bSMartin Kepplinger .channels = mma8653_channels, 1368417e008bSMartin Kepplinger .num_channels = ARRAY_SIZE(mma8653_channels), 1369417e008bSMartin Kepplinger .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, 1370605f72deSHarinath Nampally /* 1371605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1372605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1373605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1374605f72deSHarinath Nampally */ 1375605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1376605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1377605f72deSHarinath Nampally .enabled_events = MMA8452_INT_FF_MT, 1378417e008bSMartin Kepplinger }, 1379e8731180SMartin Kepplinger [fxls8471] = { 1380e8731180SMartin Kepplinger .chip_id = FXLS8471_DEVICE_ID, 1381e8731180SMartin Kepplinger .channels = mma8451_channels, 1382e8731180SMartin Kepplinger .num_channels = ARRAY_SIZE(mma8451_channels), 1383e8731180SMartin Kepplinger .mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} }, 1384605f72deSHarinath Nampally /* 1385605f72deSHarinath Nampally * Although we enable the interrupt sources once and for 1386605f72deSHarinath Nampally * all here the event detection itself is not enabled until 1387605f72deSHarinath Nampally * userspace asks for it by mma8452_write_event_config() 1388605f72deSHarinath Nampally */ 1389605f72deSHarinath Nampally .all_events = MMA8452_INT_DRDY | 1390605f72deSHarinath Nampally MMA8452_INT_TRANS | 1391605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1392605f72deSHarinath Nampally .enabled_events = MMA8452_INT_TRANS | 1393605f72deSHarinath Nampally MMA8452_INT_FF_MT, 1394e8731180SMartin Kepplinger }, 1395c3cdd6e4SMartin Kepplinger }; 1396c3cdd6e4SMartin Kepplinger 1397c7eeea93SPeter Meerwald static struct attribute *mma8452_attributes[] = { 1398c7eeea93SPeter Meerwald &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 1399c7eeea93SPeter Meerwald &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 14001e79841aSMartin Fuzzey &iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr, 1401ed859fc1SMartin Kepplinger &iio_dev_attr_in_accel_oversampling_ratio_available.dev_attr.attr, 1402c7eeea93SPeter Meerwald NULL 1403c7eeea93SPeter Meerwald }; 1404c7eeea93SPeter Meerwald 1405c7eeea93SPeter Meerwald static const struct attribute_group mma8452_group = { 1406c7eeea93SPeter Meerwald .attrs = mma8452_attributes, 1407c7eeea93SPeter Meerwald }; 1408c7eeea93SPeter Meerwald 1409c7eeea93SPeter Meerwald static const struct iio_info mma8452_info = { 1410c7eeea93SPeter Meerwald .attrs = &mma8452_group, 1411c7eeea93SPeter Meerwald .read_raw = &mma8452_read_raw, 1412c7eeea93SPeter Meerwald .write_raw = &mma8452_write_raw, 141328e34278SMartin Fuzzey .event_attrs = &mma8452_event_attribute_group, 14144febd9f1SHarinath Nampally .read_event_value = &mma8452_read_event_value, 14154febd9f1SHarinath Nampally .write_event_value = &mma8452_write_event_value, 141628e34278SMartin Fuzzey .read_event_config = &mma8452_read_event_config, 141728e34278SMartin Fuzzey .write_event_config = &mma8452_write_event_config, 14182a17698cSMartin Fuzzey .debugfs_reg_access = &mma8452_reg_access_dbg, 1419c7eeea93SPeter Meerwald }; 1420c7eeea93SPeter Meerwald 1421c7eeea93SPeter Meerwald static const unsigned long mma8452_scan_masks[] = {0x7, 0}; 1422c7eeea93SPeter Meerwald 1423ae6d9ce0SMartin Fuzzey static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig, 1424ae6d9ce0SMartin Fuzzey bool state) 1425ae6d9ce0SMartin Fuzzey { 1426ae6d9ce0SMartin Fuzzey struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 1427ae6d9ce0SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 142896c0cb2bSMartin Kepplinger int reg, ret; 142996c0cb2bSMartin Kepplinger 143096c0cb2bSMartin Kepplinger ret = mma8452_set_runtime_pm_state(data->client, state); 143196c0cb2bSMartin Kepplinger if (ret) 143296c0cb2bSMartin Kepplinger return ret; 1433ae6d9ce0SMartin Fuzzey 1434ae6d9ce0SMartin Fuzzey reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4); 1435ae6d9ce0SMartin Fuzzey if (reg < 0) 1436ae6d9ce0SMartin Fuzzey return reg; 1437ae6d9ce0SMartin Fuzzey 1438ae6d9ce0SMartin Fuzzey if (state) 1439ae6d9ce0SMartin Fuzzey reg |= MMA8452_INT_DRDY; 1440ae6d9ce0SMartin Fuzzey else 1441ae6d9ce0SMartin Fuzzey reg &= ~MMA8452_INT_DRDY; 1442ae6d9ce0SMartin Fuzzey 1443ae6d9ce0SMartin Fuzzey return mma8452_change_config(data, MMA8452_CTRL_REG4, reg); 1444ae6d9ce0SMartin Fuzzey } 1445ae6d9ce0SMartin Fuzzey 1446ae6d9ce0SMartin Fuzzey static const struct iio_trigger_ops mma8452_trigger_ops = { 1447ae6d9ce0SMartin Fuzzey .set_trigger_state = mma8452_data_rdy_trigger_set_state, 144819808e04SLars-Peter Clausen .validate_device = iio_trigger_validate_own_device, 1449ae6d9ce0SMartin Fuzzey }; 1450ae6d9ce0SMartin Fuzzey 1451ae6d9ce0SMartin Fuzzey static int mma8452_trigger_setup(struct iio_dev *indio_dev) 1452ae6d9ce0SMartin Fuzzey { 1453ae6d9ce0SMartin Fuzzey struct mma8452_data *data = iio_priv(indio_dev); 1454ae6d9ce0SMartin Fuzzey struct iio_trigger *trig; 1455ae6d9ce0SMartin Fuzzey int ret; 1456ae6d9ce0SMartin Fuzzey 1457ae6d9ce0SMartin Fuzzey trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d", 1458ae6d9ce0SMartin Fuzzey indio_dev->name, 1459ae6d9ce0SMartin Fuzzey indio_dev->id); 1460ae6d9ce0SMartin Fuzzey if (!trig) 1461ae6d9ce0SMartin Fuzzey return -ENOMEM; 1462ae6d9ce0SMartin Fuzzey 1463ae6d9ce0SMartin Fuzzey trig->dev.parent = &data->client->dev; 1464ae6d9ce0SMartin Fuzzey trig->ops = &mma8452_trigger_ops; 1465ae6d9ce0SMartin Fuzzey iio_trigger_set_drvdata(trig, indio_dev); 1466ae6d9ce0SMartin Fuzzey 1467ae6d9ce0SMartin Fuzzey ret = iio_trigger_register(trig); 1468ae6d9ce0SMartin Fuzzey if (ret) 1469ae6d9ce0SMartin Fuzzey return ret; 1470ae6d9ce0SMartin Fuzzey 1471ae6d9ce0SMartin Fuzzey indio_dev->trig = trig; 1472686027fbSHartmut Knaack 1473ae6d9ce0SMartin Fuzzey return 0; 1474ae6d9ce0SMartin Fuzzey } 1475ae6d9ce0SMartin Fuzzey 1476ae6d9ce0SMartin Fuzzey static void mma8452_trigger_cleanup(struct iio_dev *indio_dev) 1477ae6d9ce0SMartin Fuzzey { 1478ae6d9ce0SMartin Fuzzey if (indio_dev->trig) 1479ae6d9ce0SMartin Fuzzey iio_trigger_unregister(indio_dev->trig); 1480ae6d9ce0SMartin Fuzzey } 1481ae6d9ce0SMartin Fuzzey 1482ecabae71SMartin Fuzzey static int mma8452_reset(struct i2c_client *client) 1483ecabae71SMartin Fuzzey { 1484ecabae71SMartin Fuzzey int i; 1485ecabae71SMartin Fuzzey int ret; 1486ecabae71SMartin Fuzzey 1487ecabae71SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2, 1488ecabae71SMartin Fuzzey MMA8452_CTRL_REG2_RST); 1489ecabae71SMartin Fuzzey if (ret < 0) 1490ecabae71SMartin Fuzzey return ret; 1491ecabae71SMartin Fuzzey 1492ecabae71SMartin Fuzzey for (i = 0; i < 10; i++) { 1493ecabae71SMartin Fuzzey usleep_range(100, 200); 1494ecabae71SMartin Fuzzey ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2); 1495ecabae71SMartin Fuzzey if (ret == -EIO) 1496ecabae71SMartin Fuzzey continue; /* I2C comm reset */ 1497ecabae71SMartin Fuzzey if (ret < 0) 1498ecabae71SMartin Fuzzey return ret; 1499ecabae71SMartin Fuzzey if (!(ret & MMA8452_CTRL_REG2_RST)) 1500ecabae71SMartin Fuzzey return 0; 1501ecabae71SMartin Fuzzey } 1502ecabae71SMartin Fuzzey 1503ecabae71SMartin Fuzzey return -ETIMEDOUT; 1504ecabae71SMartin Fuzzey } 1505ecabae71SMartin Fuzzey 1506c3cdd6e4SMartin Kepplinger static const struct of_device_id mma8452_dt_ids[] = { 1507244a93f6SMartin Kepplinger { .compatible = "fsl,mma8451", .data = &mma_chip_info_table[mma8451] }, 1508c3cdd6e4SMartin Kepplinger { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] }, 1509c5ea1b58SMartin Kepplinger { .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] }, 1510417e008bSMartin Kepplinger { .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] }, 1511417e008bSMartin Kepplinger { .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] }, 1512e8731180SMartin Kepplinger { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] }, 1513c3cdd6e4SMartin Kepplinger { } 1514c3cdd6e4SMartin Kepplinger }; 1515c3cdd6e4SMartin Kepplinger MODULE_DEVICE_TABLE(of, mma8452_dt_ids); 1516c3cdd6e4SMartin Kepplinger 1517c7eeea93SPeter Meerwald static int mma8452_probe(struct i2c_client *client, 1518c7eeea93SPeter Meerwald const struct i2c_device_id *id) 1519c7eeea93SPeter Meerwald { 1520c7eeea93SPeter Meerwald struct mma8452_data *data; 1521c7eeea93SPeter Meerwald struct iio_dev *indio_dev; 1522c7eeea93SPeter Meerwald int ret; 1523c3cdd6e4SMartin Kepplinger const struct of_device_id *match; 1524c7eeea93SPeter Meerwald 1525c3cdd6e4SMartin Kepplinger match = of_match_device(mma8452_dt_ids, &client->dev); 1526c3cdd6e4SMartin Kepplinger if (!match) { 1527c3cdd6e4SMartin Kepplinger dev_err(&client->dev, "unknown device model\n"); 1528c3cdd6e4SMartin Kepplinger return -ENODEV; 1529c3cdd6e4SMartin Kepplinger } 1530c3cdd6e4SMartin Kepplinger 1531c7eeea93SPeter Meerwald indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 1532c7eeea93SPeter Meerwald if (!indio_dev) 1533c7eeea93SPeter Meerwald return -ENOMEM; 1534c7eeea93SPeter Meerwald 1535c7eeea93SPeter Meerwald data = iio_priv(indio_dev); 1536c7eeea93SPeter Meerwald data->client = client; 1537c7eeea93SPeter Meerwald mutex_init(&data->lock); 1538c3cdd6e4SMartin Kepplinger data->chip_info = match->data; 1539c3cdd6e4SMartin Kepplinger 1540f6ff49b8SAnson Huang data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); 1541f6ff49b8SAnson Huang if (IS_ERR(data->vdd_reg)) { 1542f6ff49b8SAnson Huang if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER) 1543f6ff49b8SAnson Huang return -EPROBE_DEFER; 1544f6ff49b8SAnson Huang 1545f6ff49b8SAnson Huang dev_err(&client->dev, "failed to get VDD regulator!\n"); 1546f6ff49b8SAnson Huang return PTR_ERR(data->vdd_reg); 1547f6ff49b8SAnson Huang } 1548f6ff49b8SAnson Huang 1549f6ff49b8SAnson Huang data->vddio_reg = devm_regulator_get(&client->dev, "vddio"); 1550f6ff49b8SAnson Huang if (IS_ERR(data->vddio_reg)) { 1551f6ff49b8SAnson Huang if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER) 1552f6ff49b8SAnson Huang return -EPROBE_DEFER; 1553f6ff49b8SAnson Huang 1554f6ff49b8SAnson Huang dev_err(&client->dev, "failed to get VDDIO regulator!\n"); 1555f6ff49b8SAnson Huang return PTR_ERR(data->vddio_reg); 1556f6ff49b8SAnson Huang } 1557f6ff49b8SAnson Huang 1558f6ff49b8SAnson Huang ret = regulator_enable(data->vdd_reg); 1559f6ff49b8SAnson Huang if (ret) { 1560f6ff49b8SAnson Huang dev_err(&client->dev, "failed to enable VDD regulator!\n"); 1561f6ff49b8SAnson Huang return ret; 1562f6ff49b8SAnson Huang } 1563f6ff49b8SAnson Huang 1564f6ff49b8SAnson Huang ret = regulator_enable(data->vddio_reg); 1565f6ff49b8SAnson Huang if (ret) { 1566f6ff49b8SAnson Huang dev_err(&client->dev, "failed to enable VDDIO regulator!\n"); 1567f6ff49b8SAnson Huang goto disable_regulator_vdd; 1568f6ff49b8SAnson Huang } 1569f6ff49b8SAnson Huang 1570417e008bSMartin Kepplinger ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); 1571417e008bSMartin Kepplinger if (ret < 0) 1572f6ff49b8SAnson Huang goto disable_regulators; 1573417e008bSMartin Kepplinger 1574417e008bSMartin Kepplinger switch (ret) { 1575244a93f6SMartin Kepplinger case MMA8451_DEVICE_ID: 1576417e008bSMartin Kepplinger case MMA8452_DEVICE_ID: 1577417e008bSMartin Kepplinger case MMA8453_DEVICE_ID: 1578417e008bSMartin Kepplinger case MMA8652_DEVICE_ID: 1579417e008bSMartin Kepplinger case MMA8653_DEVICE_ID: 1580e8731180SMartin Kepplinger case FXLS8471_DEVICE_ID: 1581417e008bSMartin Kepplinger if (ret == data->chip_info->chip_id) 1582417e008bSMartin Kepplinger break; 1583cb57f2ebSGustavo A. R. Silva /* fall through */ 1584417e008bSMartin Kepplinger default: 1585f6ff49b8SAnson Huang ret = -ENODEV; 1586f6ff49b8SAnson Huang goto disable_regulators; 1587417e008bSMartin Kepplinger } 1588417e008bSMartin Kepplinger 1589c3cdd6e4SMartin Kepplinger dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", 1590c3cdd6e4SMartin Kepplinger match->compatible, data->chip_info->chip_id); 1591c7eeea93SPeter Meerwald 1592c7eeea93SPeter Meerwald i2c_set_clientdata(client, indio_dev); 1593c7eeea93SPeter Meerwald indio_dev->info = &mma8452_info; 1594c7eeea93SPeter Meerwald indio_dev->name = id->name; 1595c7eeea93SPeter Meerwald indio_dev->dev.parent = &client->dev; 1596c7eeea93SPeter Meerwald indio_dev->modes = INDIO_DIRECT_MODE; 1597c3cdd6e4SMartin Kepplinger indio_dev->channels = data->chip_info->channels; 1598c3cdd6e4SMartin Kepplinger indio_dev->num_channels = data->chip_info->num_channels; 1599c7eeea93SPeter Meerwald indio_dev->available_scan_masks = mma8452_scan_masks; 1600c7eeea93SPeter Meerwald 1601ecabae71SMartin Fuzzey ret = mma8452_reset(client); 1602c7eeea93SPeter Meerwald if (ret < 0) 1603f6ff49b8SAnson Huang goto disable_regulators; 1604c7eeea93SPeter Meerwald 1605c7eeea93SPeter Meerwald data->data_cfg = MMA8452_DATA_CFG_FS_2G; 1606c7eeea93SPeter Meerwald ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, 1607c7eeea93SPeter Meerwald data->data_cfg); 1608c7eeea93SPeter Meerwald if (ret < 0) 1609f6ff49b8SAnson Huang goto disable_regulators; 1610c7eeea93SPeter Meerwald 161128e34278SMartin Fuzzey /* 161228e34278SMartin Fuzzey * By default set transient threshold to max to avoid events if 161328e34278SMartin Fuzzey * enabling without configuring threshold. 161428e34278SMartin Fuzzey */ 161528e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS, 161628e34278SMartin Fuzzey MMA8452_TRANSIENT_THS_MASK); 161728e34278SMartin Fuzzey if (ret < 0) 1618f6ff49b8SAnson Huang goto disable_regulators; 161928e34278SMartin Fuzzey 162028e34278SMartin Fuzzey if (client->irq) { 1621d2a3e093SMartin Kepplinger int irq2; 162228e34278SMartin Fuzzey 1623d2a3e093SMartin Kepplinger irq2 = of_irq_get_byname(client->dev.of_node, "INT2"); 1624d2a3e093SMartin Kepplinger 1625d2a3e093SMartin Kepplinger if (irq2 == client->irq) { 1626d2a3e093SMartin Kepplinger dev_dbg(&client->dev, "using interrupt line INT2\n"); 1627d2a3e093SMartin Kepplinger } else { 162828e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, 162928e34278SMartin Fuzzey MMA8452_CTRL_REG5, 1630605f72deSHarinath Nampally data->chip_info->all_events); 163128e34278SMartin Fuzzey if (ret < 0) 1632f6ff49b8SAnson Huang goto disable_regulators; 163328e34278SMartin Fuzzey 1634d2a3e093SMartin Kepplinger dev_dbg(&client->dev, "using interrupt line INT1\n"); 1635d2a3e093SMartin Kepplinger } 1636d2a3e093SMartin Kepplinger 163728e34278SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, 163828e34278SMartin Fuzzey MMA8452_CTRL_REG4, 1639605f72deSHarinath Nampally data->chip_info->enabled_events); 1640ae6d9ce0SMartin Fuzzey if (ret < 0) 1641f6ff49b8SAnson Huang goto disable_regulators; 1642ae6d9ce0SMartin Fuzzey 1643ae6d9ce0SMartin Fuzzey ret = mma8452_trigger_setup(indio_dev); 164428e34278SMartin Fuzzey if (ret < 0) 1645f6ff49b8SAnson Huang goto disable_regulators; 164628e34278SMartin Fuzzey } 164728e34278SMartin Fuzzey 1648ecabae71SMartin Fuzzey data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | 1649ecabae71SMartin Fuzzey (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); 1650a45d1238SRichard Tresidder 1651a45d1238SRichard Tresidder data->sleep_val = mma8452_calculate_sleep(data); 1652a45d1238SRichard Tresidder 1653ecabae71SMartin Fuzzey ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1, 1654ecabae71SMartin Fuzzey data->ctrl_reg1); 1655ecabae71SMartin Fuzzey if (ret < 0) 1656ae6d9ce0SMartin Fuzzey goto trigger_cleanup; 1657ecabae71SMartin Fuzzey 1658c7eeea93SPeter Meerwald ret = iio_triggered_buffer_setup(indio_dev, NULL, 1659c7eeea93SPeter Meerwald mma8452_trigger_handler, NULL); 1660c7eeea93SPeter Meerwald if (ret < 0) 1661ae6d9ce0SMartin Fuzzey goto trigger_cleanup; 1662c7eeea93SPeter Meerwald 166328e34278SMartin Fuzzey if (client->irq) { 166428e34278SMartin Fuzzey ret = devm_request_threaded_irq(&client->dev, 166528e34278SMartin Fuzzey client->irq, 166628e34278SMartin Fuzzey NULL, mma8452_interrupt, 166728e34278SMartin Fuzzey IRQF_TRIGGER_LOW | IRQF_ONESHOT, 166828e34278SMartin Fuzzey client->name, indio_dev); 166928e34278SMartin Fuzzey if (ret) 167028e34278SMartin Fuzzey goto buffer_cleanup; 167128e34278SMartin Fuzzey } 167228e34278SMartin Fuzzey 167396c0cb2bSMartin Kepplinger ret = pm_runtime_set_active(&client->dev); 167496c0cb2bSMartin Kepplinger if (ret < 0) 167596c0cb2bSMartin Kepplinger goto buffer_cleanup; 167696c0cb2bSMartin Kepplinger 167796c0cb2bSMartin Kepplinger pm_runtime_enable(&client->dev); 167896c0cb2bSMartin Kepplinger pm_runtime_set_autosuspend_delay(&client->dev, 167996c0cb2bSMartin Kepplinger MMA8452_AUTO_SUSPEND_DELAY_MS); 168096c0cb2bSMartin Kepplinger pm_runtime_use_autosuspend(&client->dev); 168196c0cb2bSMartin Kepplinger 1682c7eeea93SPeter Meerwald ret = iio_device_register(indio_dev); 1683c7eeea93SPeter Meerwald if (ret < 0) 1684c7eeea93SPeter Meerwald goto buffer_cleanup; 168528e34278SMartin Fuzzey 16864b04266aSMartin Kepplinger ret = mma8452_set_freefall_mode(data, false); 16871a965d40SBijosh Thykkoottathil if (ret < 0) 1688*d7369ae1SChuhong Yuan goto unregister_device; 16894b04266aSMartin Kepplinger 1690c7eeea93SPeter Meerwald return 0; 1691c7eeea93SPeter Meerwald 1692*d7369ae1SChuhong Yuan unregister_device: 1693*d7369ae1SChuhong Yuan iio_device_unregister(indio_dev); 1694*d7369ae1SChuhong Yuan 1695c7eeea93SPeter Meerwald buffer_cleanup: 1696c7eeea93SPeter Meerwald iio_triggered_buffer_cleanup(indio_dev); 1697ae6d9ce0SMartin Fuzzey 1698ae6d9ce0SMartin Fuzzey trigger_cleanup: 1699ae6d9ce0SMartin Fuzzey mma8452_trigger_cleanup(indio_dev); 1700ae6d9ce0SMartin Fuzzey 1701f6ff49b8SAnson Huang disable_regulators: 1702f6ff49b8SAnson Huang regulator_disable(data->vddio_reg); 1703f6ff49b8SAnson Huang 1704f6ff49b8SAnson Huang disable_regulator_vdd: 1705f6ff49b8SAnson Huang regulator_disable(data->vdd_reg); 1706f6ff49b8SAnson Huang 1707c7eeea93SPeter Meerwald return ret; 1708c7eeea93SPeter Meerwald } 1709c7eeea93SPeter Meerwald 1710c7eeea93SPeter Meerwald static int mma8452_remove(struct i2c_client *client) 1711c7eeea93SPeter Meerwald { 1712c7eeea93SPeter Meerwald struct iio_dev *indio_dev = i2c_get_clientdata(client); 1713f6ff49b8SAnson Huang struct mma8452_data *data = iio_priv(indio_dev); 1714c7eeea93SPeter Meerwald 1715c7eeea93SPeter Meerwald iio_device_unregister(indio_dev); 171696c0cb2bSMartin Kepplinger 171796c0cb2bSMartin Kepplinger pm_runtime_disable(&client->dev); 171896c0cb2bSMartin Kepplinger pm_runtime_set_suspended(&client->dev); 171996c0cb2bSMartin Kepplinger pm_runtime_put_noidle(&client->dev); 172096c0cb2bSMartin Kepplinger 1721c7eeea93SPeter Meerwald iio_triggered_buffer_cleanup(indio_dev); 1722ae6d9ce0SMartin Fuzzey mma8452_trigger_cleanup(indio_dev); 1723c7eeea93SPeter Meerwald mma8452_standby(iio_priv(indio_dev)); 1724c7eeea93SPeter Meerwald 1725f6ff49b8SAnson Huang regulator_disable(data->vddio_reg); 1726f6ff49b8SAnson Huang regulator_disable(data->vdd_reg); 1727f6ff49b8SAnson Huang 1728c7eeea93SPeter Meerwald return 0; 1729c7eeea93SPeter Meerwald } 1730c7eeea93SPeter Meerwald 173196c0cb2bSMartin Kepplinger #ifdef CONFIG_PM 173296c0cb2bSMartin Kepplinger static int mma8452_runtime_suspend(struct device *dev) 173396c0cb2bSMartin Kepplinger { 173496c0cb2bSMartin Kepplinger struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 173596c0cb2bSMartin Kepplinger struct mma8452_data *data = iio_priv(indio_dev); 173696c0cb2bSMartin Kepplinger int ret; 173796c0cb2bSMartin Kepplinger 173896c0cb2bSMartin Kepplinger mutex_lock(&data->lock); 173996c0cb2bSMartin Kepplinger ret = mma8452_standby(data); 174096c0cb2bSMartin Kepplinger mutex_unlock(&data->lock); 174196c0cb2bSMartin Kepplinger if (ret < 0) { 174296c0cb2bSMartin Kepplinger dev_err(&data->client->dev, "powering off device failed\n"); 174396c0cb2bSMartin Kepplinger return -EAGAIN; 174496c0cb2bSMartin Kepplinger } 174596c0cb2bSMartin Kepplinger 1746f6ff49b8SAnson Huang ret = regulator_disable(data->vddio_reg); 1747f6ff49b8SAnson Huang if (ret) { 1748f6ff49b8SAnson Huang dev_err(dev, "failed to disable VDDIO regulator\n"); 1749f6ff49b8SAnson Huang return ret; 1750f6ff49b8SAnson Huang } 1751f6ff49b8SAnson Huang 1752f6ff49b8SAnson Huang ret = regulator_disable(data->vdd_reg); 1753f6ff49b8SAnson Huang if (ret) { 1754f6ff49b8SAnson Huang dev_err(dev, "failed to disable VDD regulator\n"); 1755f6ff49b8SAnson Huang return ret; 1756f6ff49b8SAnson Huang } 1757f6ff49b8SAnson Huang 175896c0cb2bSMartin Kepplinger return 0; 175996c0cb2bSMartin Kepplinger } 176096c0cb2bSMartin Kepplinger 176196c0cb2bSMartin Kepplinger static int mma8452_runtime_resume(struct device *dev) 176296c0cb2bSMartin Kepplinger { 176396c0cb2bSMartin Kepplinger struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 176496c0cb2bSMartin Kepplinger struct mma8452_data *data = iio_priv(indio_dev); 176596c0cb2bSMartin Kepplinger int ret, sleep_val; 176696c0cb2bSMartin Kepplinger 1767f6ff49b8SAnson Huang ret = regulator_enable(data->vdd_reg); 1768f6ff49b8SAnson Huang if (ret) { 1769f6ff49b8SAnson Huang dev_err(dev, "failed to enable VDD regulator\n"); 1770f6ff49b8SAnson Huang return ret; 1771f6ff49b8SAnson Huang } 1772f6ff49b8SAnson Huang 1773f6ff49b8SAnson Huang ret = regulator_enable(data->vddio_reg); 1774f6ff49b8SAnson Huang if (ret) { 1775f6ff49b8SAnson Huang dev_err(dev, "failed to enable VDDIO regulator\n"); 1776f6ff49b8SAnson Huang regulator_disable(data->vdd_reg); 1777f6ff49b8SAnson Huang return ret; 1778f6ff49b8SAnson Huang } 1779f6ff49b8SAnson Huang 178096c0cb2bSMartin Kepplinger ret = mma8452_active(data); 178196c0cb2bSMartin Kepplinger if (ret < 0) 1782f6ff49b8SAnson Huang goto runtime_resume_failed; 178396c0cb2bSMartin Kepplinger 178496c0cb2bSMartin Kepplinger ret = mma8452_get_odr_index(data); 178596c0cb2bSMartin Kepplinger sleep_val = 1000 / mma8452_samp_freq[ret][0]; 178696c0cb2bSMartin Kepplinger if (sleep_val < 20) 178796c0cb2bSMartin Kepplinger usleep_range(sleep_val * 1000, 20000); 178896c0cb2bSMartin Kepplinger else 178996c0cb2bSMartin Kepplinger msleep_interruptible(sleep_val); 179096c0cb2bSMartin Kepplinger 179196c0cb2bSMartin Kepplinger return 0; 179296c0cb2bSMartin Kepplinger 1793f6ff49b8SAnson Huang runtime_resume_failed: 1794f6ff49b8SAnson Huang regulator_disable(data->vddio_reg); 1795f6ff49b8SAnson Huang regulator_disable(data->vdd_reg); 1796c7eeea93SPeter Meerwald 1797f6ff49b8SAnson Huang return ret; 1798c7eeea93SPeter Meerwald } 1799c7eeea93SPeter Meerwald #endif 1800c7eeea93SPeter Meerwald 180196c0cb2bSMartin Kepplinger static const struct dev_pm_ops mma8452_pm_ops = { 1802f6ff49b8SAnson Huang SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) 180396c0cb2bSMartin Kepplinger SET_RUNTIME_PM_OPS(mma8452_runtime_suspend, 180496c0cb2bSMartin Kepplinger mma8452_runtime_resume, NULL) 180596c0cb2bSMartin Kepplinger }; 180696c0cb2bSMartin Kepplinger 1807c7eeea93SPeter Meerwald static const struct i2c_device_id mma8452_id[] = { 1808ddb851afSMartin Kepplinger { "mma8451", mma8451 }, 1809c3cdd6e4SMartin Kepplinger { "mma8452", mma8452 }, 1810c5ea1b58SMartin Kepplinger { "mma8453", mma8453 }, 1811417e008bSMartin Kepplinger { "mma8652", mma8652 }, 1812417e008bSMartin Kepplinger { "mma8653", mma8653 }, 1813e8731180SMartin Kepplinger { "fxls8471", fxls8471 }, 1814c7eeea93SPeter Meerwald { } 1815c7eeea93SPeter Meerwald }; 1816c7eeea93SPeter Meerwald MODULE_DEVICE_TABLE(i2c, mma8452_id); 1817c7eeea93SPeter Meerwald 1818c7eeea93SPeter Meerwald static struct i2c_driver mma8452_driver = { 1819c7eeea93SPeter Meerwald .driver = { 1820c7eeea93SPeter Meerwald .name = "mma8452", 1821a3fb96a8SMartin Fuzzey .of_match_table = of_match_ptr(mma8452_dt_ids), 182296c0cb2bSMartin Kepplinger .pm = &mma8452_pm_ops, 1823c7eeea93SPeter Meerwald }, 1824c7eeea93SPeter Meerwald .probe = mma8452_probe, 1825c7eeea93SPeter Meerwald .remove = mma8452_remove, 1826c7eeea93SPeter Meerwald .id_table = mma8452_id, 1827c7eeea93SPeter Meerwald }; 1828c7eeea93SPeter Meerwald module_i2c_driver(mma8452_driver); 1829c7eeea93SPeter Meerwald 1830c7eeea93SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 1831f26ab1aaSMartin Kepplinger MODULE_DESCRIPTION("Freescale / NXP MMA8452 accelerometer driver"); 1832c7eeea93SPeter Meerwald MODULE_LICENSE("GPL"); 1833