1c78b9171SVlad Dogaru /* 2c78b9171SVlad Dogaru * Freescale MMA9551L Intelligent Motion-Sensing Platform driver 3c78b9171SVlad Dogaru * Copyright (c) 2014, Intel Corporation. 4c78b9171SVlad Dogaru * 5c78b9171SVlad Dogaru * This program is free software; you can redistribute it and/or modify it 6c78b9171SVlad Dogaru * under the terms and conditions of the GNU General Public License, 7c78b9171SVlad Dogaru * version 2, as published by the Free Software Foundation. 8c78b9171SVlad Dogaru * 9c78b9171SVlad Dogaru * This program is distributed in the hope it will be useful, but WITHOUT 10c78b9171SVlad Dogaru * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11c78b9171SVlad Dogaru * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12c78b9171SVlad Dogaru * more details. 13c78b9171SVlad Dogaru */ 14c78b9171SVlad Dogaru 15c78b9171SVlad Dogaru #include <linux/module.h> 16c78b9171SVlad Dogaru #include <linux/i2c.h> 17c78b9171SVlad Dogaru #include <linux/interrupt.h> 18c78b9171SVlad Dogaru #include <linux/slab.h> 19c78b9171SVlad Dogaru #include <linux/acpi.h> 20c78b9171SVlad Dogaru #include <linux/delay.h> 21c78b9171SVlad Dogaru #include <linux/gpio/consumer.h> 22c78b9171SVlad Dogaru #include <linux/iio/iio.h> 23c78b9171SVlad Dogaru #include <linux/iio/sysfs.h> 24c78b9171SVlad Dogaru #include <linux/iio/events.h> 256da93a67SIrina Tirdea #include <linux/pm_runtime.h> 26d5b97f5cSIrina Tirdea #include "mma9551_core.h" 27c78b9171SVlad Dogaru 28c78b9171SVlad Dogaru #define MMA9551_DRV_NAME "mma9551" 29c78b9171SVlad Dogaru #define MMA9551_IRQ_NAME "mma9551_event" 30c78b9171SVlad Dogaru #define MMA9551_GPIO_COUNT 4 31c78b9171SVlad Dogaru 32c78b9171SVlad Dogaru /* Tilt application (inclination in IIO terms). */ 33c78b9171SVlad Dogaru #define MMA9551_TILT_XZ_ANG_REG 0x00 34c78b9171SVlad Dogaru #define MMA9551_TILT_YZ_ANG_REG 0x01 35c78b9171SVlad Dogaru #define MMA9551_TILT_XY_ANG_REG 0x02 36c78b9171SVlad Dogaru #define MMA9551_TILT_ANGFLG BIT(7) 37c78b9171SVlad Dogaru #define MMA9551_TILT_QUAD_REG 0x03 38c78b9171SVlad Dogaru #define MMA9551_TILT_XY_QUAD_SHIFT 0 39c78b9171SVlad Dogaru #define MMA9551_TILT_YZ_QUAD_SHIFT 2 40c78b9171SVlad Dogaru #define MMA9551_TILT_XZ_QUAD_SHIFT 4 41c78b9171SVlad Dogaru #define MMA9551_TILT_CFG_REG 0x01 42c78b9171SVlad Dogaru #define MMA9551_TILT_ANG_THRESH_MASK GENMASK(3, 0) 43c78b9171SVlad Dogaru 44d5b97f5cSIrina Tirdea #define MMA9551_DEFAULT_SAMPLE_RATE 122 /* Hz */ 45d5b97f5cSIrina Tirdea 46c78b9171SVlad Dogaru /* Tilt events are mapped to the first three GPIO pins. */ 47c78b9171SVlad Dogaru enum mma9551_tilt_axis { 48c78b9171SVlad Dogaru mma9551_x = 0, 49c78b9171SVlad Dogaru mma9551_y, 50c78b9171SVlad Dogaru mma9551_z, 51c78b9171SVlad Dogaru }; 52c78b9171SVlad Dogaru 53c78b9171SVlad Dogaru struct mma9551_data { 54c78b9171SVlad Dogaru struct i2c_client *client; 55c78b9171SVlad Dogaru struct mutex mutex; 56c78b9171SVlad Dogaru int event_enabled[3]; 57c78b9171SVlad Dogaru int irqs[MMA9551_GPIO_COUNT]; 58c78b9171SVlad Dogaru }; 59c78b9171SVlad Dogaru 60c78b9171SVlad Dogaru static int mma9551_read_incli_chan(struct i2c_client *client, 61c78b9171SVlad Dogaru const struct iio_chan_spec *chan, 62c78b9171SVlad Dogaru int *val) 63c78b9171SVlad Dogaru { 64c78b9171SVlad Dogaru u8 quad_shift, angle, quadrant; 65c78b9171SVlad Dogaru u16 reg_addr; 66c78b9171SVlad Dogaru int ret; 67c78b9171SVlad Dogaru 68c78b9171SVlad Dogaru switch (chan->channel2) { 69c78b9171SVlad Dogaru case IIO_MOD_X: 70c78b9171SVlad Dogaru reg_addr = MMA9551_TILT_YZ_ANG_REG; 71c78b9171SVlad Dogaru quad_shift = MMA9551_TILT_YZ_QUAD_SHIFT; 72c78b9171SVlad Dogaru break; 73c78b9171SVlad Dogaru case IIO_MOD_Y: 74c78b9171SVlad Dogaru reg_addr = MMA9551_TILT_XZ_ANG_REG; 75c78b9171SVlad Dogaru quad_shift = MMA9551_TILT_XZ_QUAD_SHIFT; 76c78b9171SVlad Dogaru break; 77c78b9171SVlad Dogaru case IIO_MOD_Z: 78c78b9171SVlad Dogaru reg_addr = MMA9551_TILT_XY_ANG_REG; 79c78b9171SVlad Dogaru quad_shift = MMA9551_TILT_XY_QUAD_SHIFT; 80c78b9171SVlad Dogaru break; 81c78b9171SVlad Dogaru default: 82c78b9171SVlad Dogaru return -EINVAL; 83c78b9171SVlad Dogaru } 84c78b9171SVlad Dogaru 856da93a67SIrina Tirdea ret = mma9551_set_power_state(client, true); 86c78b9171SVlad Dogaru if (ret < 0) 87c78b9171SVlad Dogaru return ret; 88c78b9171SVlad Dogaru 89c78b9171SVlad Dogaru ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT, 906da93a67SIrina Tirdea reg_addr, &angle); 916da93a67SIrina Tirdea if (ret < 0) 926da93a67SIrina Tirdea goto out_poweroff; 936da93a67SIrina Tirdea 946da93a67SIrina Tirdea ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT, 95c78b9171SVlad Dogaru MMA9551_TILT_QUAD_REG, &quadrant); 96c78b9171SVlad Dogaru if (ret < 0) 976da93a67SIrina Tirdea goto out_poweroff; 98c78b9171SVlad Dogaru 99c78b9171SVlad Dogaru angle &= ~MMA9551_TILT_ANGFLG; 100c78b9171SVlad Dogaru quadrant = (quadrant >> quad_shift) & 0x03; 101c78b9171SVlad Dogaru 102c78b9171SVlad Dogaru if (quadrant == 1 || quadrant == 3) 103c78b9171SVlad Dogaru *val = 90 * (quadrant + 1) - angle; 104c78b9171SVlad Dogaru else 105c78b9171SVlad Dogaru *val = angle + 90 * quadrant; 106c78b9171SVlad Dogaru 1076da93a67SIrina Tirdea ret = IIO_VAL_INT; 1086da93a67SIrina Tirdea 1096da93a67SIrina Tirdea out_poweroff: 1106da93a67SIrina Tirdea mma9551_set_power_state(client, false); 1116da93a67SIrina Tirdea return ret; 112c78b9171SVlad Dogaru } 113c78b9171SVlad Dogaru 114c78b9171SVlad Dogaru static int mma9551_read_raw(struct iio_dev *indio_dev, 115c78b9171SVlad Dogaru struct iio_chan_spec const *chan, 116c78b9171SVlad Dogaru int *val, int *val2, long mask) 117c78b9171SVlad Dogaru { 118c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 119c78b9171SVlad Dogaru int ret; 120c78b9171SVlad Dogaru 121c78b9171SVlad Dogaru switch (mask) { 122c78b9171SVlad Dogaru case IIO_CHAN_INFO_PROCESSED: 123c78b9171SVlad Dogaru switch (chan->type) { 124c78b9171SVlad Dogaru case IIO_INCLI: 125c78b9171SVlad Dogaru mutex_lock(&data->mutex); 126c78b9171SVlad Dogaru ret = mma9551_read_incli_chan(data->client, chan, val); 127c78b9171SVlad Dogaru mutex_unlock(&data->mutex); 128c78b9171SVlad Dogaru return ret; 129c78b9171SVlad Dogaru default: 130c78b9171SVlad Dogaru return -EINVAL; 131c78b9171SVlad Dogaru } 132c78b9171SVlad Dogaru case IIO_CHAN_INFO_RAW: 133c78b9171SVlad Dogaru switch (chan->type) { 134c78b9171SVlad Dogaru case IIO_ACCEL: 135c78b9171SVlad Dogaru mutex_lock(&data->mutex); 136c78b9171SVlad Dogaru ret = mma9551_read_accel_chan(data->client, 137c78b9171SVlad Dogaru chan, val, val2); 138c78b9171SVlad Dogaru mutex_unlock(&data->mutex); 139c78b9171SVlad Dogaru return ret; 140c78b9171SVlad Dogaru default: 141c78b9171SVlad Dogaru return -EINVAL; 142c78b9171SVlad Dogaru } 143c78b9171SVlad Dogaru case IIO_CHAN_INFO_SCALE: 144c78b9171SVlad Dogaru switch (chan->type) { 145c78b9171SVlad Dogaru case IIO_ACCEL: 146d5b97f5cSIrina Tirdea return mma9551_read_accel_scale(val, val2); 147c78b9171SVlad Dogaru default: 148c78b9171SVlad Dogaru return -EINVAL; 149c78b9171SVlad Dogaru } 150c78b9171SVlad Dogaru default: 151c78b9171SVlad Dogaru return -EINVAL; 152c78b9171SVlad Dogaru } 153c78b9171SVlad Dogaru } 154c78b9171SVlad Dogaru 155c78b9171SVlad Dogaru static int mma9551_read_event_config(struct iio_dev *indio_dev, 156c78b9171SVlad Dogaru const struct iio_chan_spec *chan, 157c78b9171SVlad Dogaru enum iio_event_type type, 158c78b9171SVlad Dogaru enum iio_event_direction dir) 159c78b9171SVlad Dogaru { 160c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 161c78b9171SVlad Dogaru 162c78b9171SVlad Dogaru switch (chan->type) { 163c78b9171SVlad Dogaru case IIO_INCLI: 164c78b9171SVlad Dogaru /* IIO counts axes from 1, because IIO_NO_MOD is 0. */ 165c78b9171SVlad Dogaru return data->event_enabled[chan->channel2 - 1]; 166c78b9171SVlad Dogaru default: 167c78b9171SVlad Dogaru return -EINVAL; 168c78b9171SVlad Dogaru } 169c78b9171SVlad Dogaru } 170c78b9171SVlad Dogaru 171c78b9171SVlad Dogaru static int mma9551_config_incli_event(struct iio_dev *indio_dev, 172c78b9171SVlad Dogaru enum iio_modifier axis, 173c78b9171SVlad Dogaru int state) 174c78b9171SVlad Dogaru { 175c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 176c78b9171SVlad Dogaru enum mma9551_tilt_axis mma_axis; 177c78b9171SVlad Dogaru int ret; 178c78b9171SVlad Dogaru 179c78b9171SVlad Dogaru /* IIO counts axes from 1, because IIO_NO_MOD is 0. */ 180c78b9171SVlad Dogaru mma_axis = axis - 1; 181c78b9171SVlad Dogaru 182c78b9171SVlad Dogaru if (data->event_enabled[mma_axis] == state) 183c78b9171SVlad Dogaru return 0; 184c78b9171SVlad Dogaru 185c78b9171SVlad Dogaru if (state == 0) { 18660347e71SVlad Dogaru ret = mma9551_gpio_config(data->client, 18760347e71SVlad Dogaru (enum mma9551_gpio_pin)mma_axis, 188c78b9171SVlad Dogaru MMA9551_APPID_NONE, 0, 0); 189c78b9171SVlad Dogaru if (ret < 0) 190c78b9171SVlad Dogaru return ret; 1916da93a67SIrina Tirdea 1926da93a67SIrina Tirdea ret = mma9551_set_power_state(data->client, false); 1936da93a67SIrina Tirdea if (ret < 0) 1946da93a67SIrina Tirdea return ret; 195c78b9171SVlad Dogaru } else { 196c78b9171SVlad Dogaru int bitnum; 197c78b9171SVlad Dogaru 198c78b9171SVlad Dogaru /* Bit 7 of each angle register holds the angle flag. */ 199c78b9171SVlad Dogaru switch (axis) { 200c78b9171SVlad Dogaru case IIO_MOD_X: 201c78b9171SVlad Dogaru bitnum = 7 + 8 * MMA9551_TILT_YZ_ANG_REG; 202c78b9171SVlad Dogaru break; 203c78b9171SVlad Dogaru case IIO_MOD_Y: 204c78b9171SVlad Dogaru bitnum = 7 + 8 * MMA9551_TILT_XZ_ANG_REG; 205c78b9171SVlad Dogaru break; 206c78b9171SVlad Dogaru case IIO_MOD_Z: 207c78b9171SVlad Dogaru bitnum = 7 + 8 * MMA9551_TILT_XY_ANG_REG; 208c78b9171SVlad Dogaru break; 209c78b9171SVlad Dogaru default: 210c78b9171SVlad Dogaru return -EINVAL; 211c78b9171SVlad Dogaru } 212c78b9171SVlad Dogaru 2136da93a67SIrina Tirdea 2146da93a67SIrina Tirdea ret = mma9551_set_power_state(data->client, true); 2156da93a67SIrina Tirdea if (ret < 0) 2166da93a67SIrina Tirdea return ret; 2176da93a67SIrina Tirdea 21860347e71SVlad Dogaru ret = mma9551_gpio_config(data->client, 21960347e71SVlad Dogaru (enum mma9551_gpio_pin)mma_axis, 220c78b9171SVlad Dogaru MMA9551_APPID_TILT, bitnum, 0); 2216da93a67SIrina Tirdea if (ret < 0) { 2226da93a67SIrina Tirdea mma9551_set_power_state(data->client, false); 223c78b9171SVlad Dogaru return ret; 224c78b9171SVlad Dogaru } 2256da93a67SIrina Tirdea } 226c78b9171SVlad Dogaru 227c78b9171SVlad Dogaru data->event_enabled[mma_axis] = state; 228c78b9171SVlad Dogaru 229c78b9171SVlad Dogaru return ret; 230c78b9171SVlad Dogaru } 231c78b9171SVlad Dogaru 232c78b9171SVlad Dogaru static int mma9551_write_event_config(struct iio_dev *indio_dev, 233c78b9171SVlad Dogaru const struct iio_chan_spec *chan, 234c78b9171SVlad Dogaru enum iio_event_type type, 235c78b9171SVlad Dogaru enum iio_event_direction dir, 236c78b9171SVlad Dogaru int state) 237c78b9171SVlad Dogaru { 238c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 239c78b9171SVlad Dogaru int ret; 240c78b9171SVlad Dogaru 241c78b9171SVlad Dogaru switch (chan->type) { 242c78b9171SVlad Dogaru case IIO_INCLI: 243c78b9171SVlad Dogaru mutex_lock(&data->mutex); 244c78b9171SVlad Dogaru ret = mma9551_config_incli_event(indio_dev, 245c78b9171SVlad Dogaru chan->channel2, state); 246c78b9171SVlad Dogaru mutex_unlock(&data->mutex); 247c78b9171SVlad Dogaru return ret; 248c78b9171SVlad Dogaru default: 249c78b9171SVlad Dogaru return -EINVAL; 250c78b9171SVlad Dogaru } 251c78b9171SVlad Dogaru } 252c78b9171SVlad Dogaru 253c78b9171SVlad Dogaru static int mma9551_write_event_value(struct iio_dev *indio_dev, 254c78b9171SVlad Dogaru const struct iio_chan_spec *chan, 255c78b9171SVlad Dogaru enum iio_event_type type, 256c78b9171SVlad Dogaru enum iio_event_direction dir, 257c78b9171SVlad Dogaru enum iio_event_info info, 258c78b9171SVlad Dogaru int val, int val2) 259c78b9171SVlad Dogaru { 260c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 261c78b9171SVlad Dogaru int ret; 262c78b9171SVlad Dogaru 263c78b9171SVlad Dogaru switch (chan->type) { 264c78b9171SVlad Dogaru case IIO_INCLI: 265c78b9171SVlad Dogaru if (val2 != 0 || val < 1 || val > 10) 266c78b9171SVlad Dogaru return -EINVAL; 267c78b9171SVlad Dogaru mutex_lock(&data->mutex); 268c78b9171SVlad Dogaru ret = mma9551_update_config_bits(data->client, 269c78b9171SVlad Dogaru MMA9551_APPID_TILT, 270c78b9171SVlad Dogaru MMA9551_TILT_CFG_REG, 271c78b9171SVlad Dogaru MMA9551_TILT_ANG_THRESH_MASK, 272c78b9171SVlad Dogaru val); 273c78b9171SVlad Dogaru mutex_unlock(&data->mutex); 274c78b9171SVlad Dogaru return ret; 275c78b9171SVlad Dogaru default: 276c78b9171SVlad Dogaru return -EINVAL; 277c78b9171SVlad Dogaru } 278c78b9171SVlad Dogaru } 279c78b9171SVlad Dogaru 280c78b9171SVlad Dogaru static int mma9551_read_event_value(struct iio_dev *indio_dev, 281c78b9171SVlad Dogaru const struct iio_chan_spec *chan, 282c78b9171SVlad Dogaru enum iio_event_type type, 283c78b9171SVlad Dogaru enum iio_event_direction dir, 284c78b9171SVlad Dogaru enum iio_event_info info, 285c78b9171SVlad Dogaru int *val, int *val2) 286c78b9171SVlad Dogaru { 287c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 288c78b9171SVlad Dogaru int ret; 289c78b9171SVlad Dogaru u8 tmp; 290c78b9171SVlad Dogaru 291c78b9171SVlad Dogaru switch (chan->type) { 292c78b9171SVlad Dogaru case IIO_INCLI: 293c78b9171SVlad Dogaru mutex_lock(&data->mutex); 294c78b9171SVlad Dogaru ret = mma9551_read_config_byte(data->client, 295c78b9171SVlad Dogaru MMA9551_APPID_TILT, 296c78b9171SVlad Dogaru MMA9551_TILT_CFG_REG, &tmp); 297c78b9171SVlad Dogaru mutex_unlock(&data->mutex); 298c78b9171SVlad Dogaru if (ret < 0) 299c78b9171SVlad Dogaru return ret; 300c78b9171SVlad Dogaru *val = tmp & MMA9551_TILT_ANG_THRESH_MASK; 301c78b9171SVlad Dogaru *val2 = 0; 302c78b9171SVlad Dogaru return IIO_VAL_INT; 303c78b9171SVlad Dogaru default: 304c78b9171SVlad Dogaru return -EINVAL; 305c78b9171SVlad Dogaru } 306c78b9171SVlad Dogaru } 307c78b9171SVlad Dogaru 308c78b9171SVlad Dogaru static const struct iio_event_spec mma9551_incli_event = { 309c78b9171SVlad Dogaru .type = IIO_EV_TYPE_ROC, 310c78b9171SVlad Dogaru .dir = IIO_EV_DIR_RISING, 311c78b9171SVlad Dogaru .mask_separate = BIT(IIO_EV_INFO_ENABLE), 312c78b9171SVlad Dogaru .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), 313c78b9171SVlad Dogaru }; 314c78b9171SVlad Dogaru 315c78b9171SVlad Dogaru #define MMA9551_INCLI_CHANNEL(axis) { \ 316c78b9171SVlad Dogaru .type = IIO_INCLI, \ 317c78b9171SVlad Dogaru .modified = 1, \ 318c78b9171SVlad Dogaru .channel2 = axis, \ 319c78b9171SVlad Dogaru .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ 320c78b9171SVlad Dogaru .event_spec = &mma9551_incli_event, \ 321c78b9171SVlad Dogaru .num_event_specs = 1, \ 322c78b9171SVlad Dogaru } 323c78b9171SVlad Dogaru 324c78b9171SVlad Dogaru static const struct iio_chan_spec mma9551_channels[] = { 325c78b9171SVlad Dogaru MMA9551_ACCEL_CHANNEL(IIO_MOD_X), 326c78b9171SVlad Dogaru MMA9551_ACCEL_CHANNEL(IIO_MOD_Y), 327c78b9171SVlad Dogaru MMA9551_ACCEL_CHANNEL(IIO_MOD_Z), 328c78b9171SVlad Dogaru 329c78b9171SVlad Dogaru MMA9551_INCLI_CHANNEL(IIO_MOD_X), 330c78b9171SVlad Dogaru MMA9551_INCLI_CHANNEL(IIO_MOD_Y), 331c78b9171SVlad Dogaru MMA9551_INCLI_CHANNEL(IIO_MOD_Z), 332c78b9171SVlad Dogaru }; 333c78b9171SVlad Dogaru 334c78b9171SVlad Dogaru static const struct iio_info mma9551_info = { 335c78b9171SVlad Dogaru .driver_module = THIS_MODULE, 336c78b9171SVlad Dogaru .read_raw = mma9551_read_raw, 337c78b9171SVlad Dogaru .read_event_config = mma9551_read_event_config, 338c78b9171SVlad Dogaru .write_event_config = mma9551_write_event_config, 339c78b9171SVlad Dogaru .read_event_value = mma9551_read_event_value, 340c78b9171SVlad Dogaru .write_event_value = mma9551_write_event_value, 341c78b9171SVlad Dogaru }; 342c78b9171SVlad Dogaru 343c78b9171SVlad Dogaru static irqreturn_t mma9551_event_handler(int irq, void *private) 344c78b9171SVlad Dogaru { 345c78b9171SVlad Dogaru struct iio_dev *indio_dev = private; 346c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 347c78b9171SVlad Dogaru int i, ret, mma_axis = -1; 348c78b9171SVlad Dogaru u16 reg; 349c78b9171SVlad Dogaru u8 val; 350c78b9171SVlad Dogaru 351c78b9171SVlad Dogaru mutex_lock(&data->mutex); 352c78b9171SVlad Dogaru 353c78b9171SVlad Dogaru for (i = 0; i < 3; i++) 354c78b9171SVlad Dogaru if (irq == data->irqs[i]) { 355c78b9171SVlad Dogaru mma_axis = i; 356c78b9171SVlad Dogaru break; 357c78b9171SVlad Dogaru } 358c78b9171SVlad Dogaru 359c78b9171SVlad Dogaru if (mma_axis == -1) { 360c78b9171SVlad Dogaru /* IRQ was triggered on 4th line, which we don't use. */ 361c78b9171SVlad Dogaru dev_warn(&data->client->dev, 362c78b9171SVlad Dogaru "irq triggered on unused line %d\n", data->irqs[3]); 363c78b9171SVlad Dogaru goto out; 364c78b9171SVlad Dogaru } 365c78b9171SVlad Dogaru 366c78b9171SVlad Dogaru switch (mma_axis) { 367c78b9171SVlad Dogaru case mma9551_x: 368c78b9171SVlad Dogaru reg = MMA9551_TILT_YZ_ANG_REG; 369c78b9171SVlad Dogaru break; 370c78b9171SVlad Dogaru case mma9551_y: 371c78b9171SVlad Dogaru reg = MMA9551_TILT_XZ_ANG_REG; 372c78b9171SVlad Dogaru break; 373c78b9171SVlad Dogaru case mma9551_z: 374c78b9171SVlad Dogaru reg = MMA9551_TILT_XY_ANG_REG; 375c78b9171SVlad Dogaru break; 376c78b9171SVlad Dogaru } 377c78b9171SVlad Dogaru 378c78b9171SVlad Dogaru /* 379c78b9171SVlad Dogaru * Read the angle even though we don't use it, otherwise we 380c78b9171SVlad Dogaru * won't get any further interrupts. 381c78b9171SVlad Dogaru */ 382c78b9171SVlad Dogaru ret = mma9551_read_status_byte(data->client, MMA9551_APPID_TILT, 383c78b9171SVlad Dogaru reg, &val); 384c78b9171SVlad Dogaru if (ret < 0) { 385c78b9171SVlad Dogaru dev_err(&data->client->dev, 386c78b9171SVlad Dogaru "error %d reading tilt register in IRQ\n", ret); 387c78b9171SVlad Dogaru goto out; 388c78b9171SVlad Dogaru } 389c78b9171SVlad Dogaru 390c78b9171SVlad Dogaru iio_push_event(indio_dev, 391c78b9171SVlad Dogaru IIO_MOD_EVENT_CODE(IIO_INCLI, 0, (mma_axis + 1), 392c78b9171SVlad Dogaru IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING), 393bc2b7dabSGregor Boirie iio_get_time_ns(indio_dev)); 394c78b9171SVlad Dogaru 395c78b9171SVlad Dogaru out: 396c78b9171SVlad Dogaru mutex_unlock(&data->mutex); 397c78b9171SVlad Dogaru 398c78b9171SVlad Dogaru return IRQ_HANDLED; 399c78b9171SVlad Dogaru } 400c78b9171SVlad Dogaru 401c78b9171SVlad Dogaru static int mma9551_init(struct mma9551_data *data) 402c78b9171SVlad Dogaru { 403c78b9171SVlad Dogaru int ret; 404c78b9171SVlad Dogaru 405c78b9171SVlad Dogaru ret = mma9551_read_version(data->client); 406c78b9171SVlad Dogaru if (ret) 407c78b9171SVlad Dogaru return ret; 408c78b9171SVlad Dogaru 4096da93a67SIrina Tirdea return mma9551_set_device_state(data->client, true); 410c78b9171SVlad Dogaru } 411c78b9171SVlad Dogaru 412c78b9171SVlad Dogaru static int mma9551_gpio_probe(struct iio_dev *indio_dev) 413c78b9171SVlad Dogaru { 414c78b9171SVlad Dogaru struct gpio_desc *gpio; 415c78b9171SVlad Dogaru int i, ret; 416c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 417c78b9171SVlad Dogaru struct device *dev = &data->client->dev; 418c78b9171SVlad Dogaru 419c78b9171SVlad Dogaru for (i = 0; i < MMA9551_GPIO_COUNT; i++) { 420ed3edc09SAndy Shevchenko gpio = devm_gpiod_get_index(dev, NULL, i, GPIOD_IN); 421c78b9171SVlad Dogaru if (IS_ERR(gpio)) { 422c78b9171SVlad Dogaru dev_err(dev, "acpi gpio get index failed\n"); 423c78b9171SVlad Dogaru return PTR_ERR(gpio); 424c78b9171SVlad Dogaru } 425c78b9171SVlad Dogaru 426debf6d84SRoberta Dobrescu ret = gpiod_to_irq(gpio); 427debf6d84SRoberta Dobrescu if (ret < 0) 428debf6d84SRoberta Dobrescu return ret; 429debf6d84SRoberta Dobrescu 430debf6d84SRoberta Dobrescu data->irqs[i] = ret; 431c78b9171SVlad Dogaru ret = devm_request_threaded_irq(dev, data->irqs[i], 432c78b9171SVlad Dogaru NULL, mma9551_event_handler, 433c78b9171SVlad Dogaru IRQF_TRIGGER_RISING | IRQF_ONESHOT, 434c78b9171SVlad Dogaru MMA9551_IRQ_NAME, indio_dev); 435c78b9171SVlad Dogaru if (ret < 0) { 436c78b9171SVlad Dogaru dev_err(dev, "request irq %d failed\n", data->irqs[i]); 437c78b9171SVlad Dogaru return ret; 438c78b9171SVlad Dogaru } 439c78b9171SVlad Dogaru 440c78b9171SVlad Dogaru dev_dbg(dev, "gpio resource, no:%d irq:%d\n", 441c78b9171SVlad Dogaru desc_to_gpio(gpio), data->irqs[i]); 442c78b9171SVlad Dogaru } 443c78b9171SVlad Dogaru 444c78b9171SVlad Dogaru return 0; 445c78b9171SVlad Dogaru } 446c78b9171SVlad Dogaru 447c78b9171SVlad Dogaru static const char *mma9551_match_acpi_device(struct device *dev) 448c78b9171SVlad Dogaru { 449c78b9171SVlad Dogaru const struct acpi_device_id *id; 450c78b9171SVlad Dogaru 451c78b9171SVlad Dogaru id = acpi_match_device(dev->driver->acpi_match_table, dev); 452c78b9171SVlad Dogaru if (!id) 453c78b9171SVlad Dogaru return NULL; 454c78b9171SVlad Dogaru 455c78b9171SVlad Dogaru return dev_name(dev); 456c78b9171SVlad Dogaru } 457c78b9171SVlad Dogaru 458c78b9171SVlad Dogaru static int mma9551_probe(struct i2c_client *client, 459c78b9171SVlad Dogaru const struct i2c_device_id *id) 460c78b9171SVlad Dogaru { 461c78b9171SVlad Dogaru struct mma9551_data *data; 462c78b9171SVlad Dogaru struct iio_dev *indio_dev; 463c78b9171SVlad Dogaru const char *name = NULL; 464c78b9171SVlad Dogaru int ret; 465c78b9171SVlad Dogaru 466c78b9171SVlad Dogaru indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 467c78b9171SVlad Dogaru if (!indio_dev) 468c78b9171SVlad Dogaru return -ENOMEM; 469c78b9171SVlad Dogaru 470c78b9171SVlad Dogaru data = iio_priv(indio_dev); 471c78b9171SVlad Dogaru i2c_set_clientdata(client, indio_dev); 472c78b9171SVlad Dogaru data->client = client; 473c78b9171SVlad Dogaru 474c78b9171SVlad Dogaru if (id) 475c78b9171SVlad Dogaru name = id->name; 476c78b9171SVlad Dogaru else if (ACPI_HANDLE(&client->dev)) 477c78b9171SVlad Dogaru name = mma9551_match_acpi_device(&client->dev); 478c78b9171SVlad Dogaru 479c78b9171SVlad Dogaru ret = mma9551_init(data); 480c78b9171SVlad Dogaru if (ret < 0) 481c78b9171SVlad Dogaru return ret; 482c78b9171SVlad Dogaru 483c78b9171SVlad Dogaru mutex_init(&data->mutex); 484c78b9171SVlad Dogaru 485c78b9171SVlad Dogaru indio_dev->dev.parent = &client->dev; 486c78b9171SVlad Dogaru indio_dev->channels = mma9551_channels; 487c78b9171SVlad Dogaru indio_dev->num_channels = ARRAY_SIZE(mma9551_channels); 488c78b9171SVlad Dogaru indio_dev->name = name; 489c78b9171SVlad Dogaru indio_dev->modes = INDIO_DIRECT_MODE; 490c78b9171SVlad Dogaru indio_dev->info = &mma9551_info; 491c78b9171SVlad Dogaru 492c78b9171SVlad Dogaru ret = mma9551_gpio_probe(indio_dev); 493c78b9171SVlad Dogaru if (ret < 0) 494c78b9171SVlad Dogaru goto out_poweroff; 495c78b9171SVlad Dogaru 4966da93a67SIrina Tirdea ret = pm_runtime_set_active(&client->dev); 4976da93a67SIrina Tirdea if (ret < 0) 4987d0ead5cSAdriana Reus goto out_poweroff; 4996da93a67SIrina Tirdea 5006da93a67SIrina Tirdea pm_runtime_enable(&client->dev); 5016da93a67SIrina Tirdea pm_runtime_set_autosuspend_delay(&client->dev, 5026da93a67SIrina Tirdea MMA9551_AUTO_SUSPEND_DELAY_MS); 5036da93a67SIrina Tirdea pm_runtime_use_autosuspend(&client->dev); 5046da93a67SIrina Tirdea 5057d0ead5cSAdriana Reus ret = iio_device_register(indio_dev); 5067d0ead5cSAdriana Reus if (ret < 0) { 5077d0ead5cSAdriana Reus dev_err(&client->dev, "unable to register iio device\n"); 5087d0ead5cSAdriana Reus goto out_poweroff; 5097d0ead5cSAdriana Reus } 5107d0ead5cSAdriana Reus 511c78b9171SVlad Dogaru return 0; 512c78b9171SVlad Dogaru 513c78b9171SVlad Dogaru out_poweroff: 514c78b9171SVlad Dogaru mma9551_set_device_state(client, false); 515c78b9171SVlad Dogaru 516c78b9171SVlad Dogaru return ret; 517c78b9171SVlad Dogaru } 518c78b9171SVlad Dogaru 519c78b9171SVlad Dogaru static int mma9551_remove(struct i2c_client *client) 520c78b9171SVlad Dogaru { 521c78b9171SVlad Dogaru struct iio_dev *indio_dev = i2c_get_clientdata(client); 522c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 523c78b9171SVlad Dogaru 5247d0ead5cSAdriana Reus iio_device_unregister(indio_dev); 5257d0ead5cSAdriana Reus 5266da93a67SIrina Tirdea pm_runtime_disable(&client->dev); 5276da93a67SIrina Tirdea pm_runtime_set_suspended(&client->dev); 5286da93a67SIrina Tirdea pm_runtime_put_noidle(&client->dev); 5296da93a67SIrina Tirdea 530c78b9171SVlad Dogaru mutex_lock(&data->mutex); 531c78b9171SVlad Dogaru mma9551_set_device_state(data->client, false); 532c78b9171SVlad Dogaru mutex_unlock(&data->mutex); 533c78b9171SVlad Dogaru 534c78b9171SVlad Dogaru return 0; 535c78b9171SVlad Dogaru } 536c78b9171SVlad Dogaru 5376da93a67SIrina Tirdea #ifdef CONFIG_PM 5386da93a67SIrina Tirdea static int mma9551_runtime_suspend(struct device *dev) 5396da93a67SIrina Tirdea { 5406da93a67SIrina Tirdea struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 5416da93a67SIrina Tirdea struct mma9551_data *data = iio_priv(indio_dev); 5426da93a67SIrina Tirdea int ret; 5436da93a67SIrina Tirdea 5446da93a67SIrina Tirdea mutex_lock(&data->mutex); 5456da93a67SIrina Tirdea ret = mma9551_set_device_state(data->client, false); 5466da93a67SIrina Tirdea mutex_unlock(&data->mutex); 5476da93a67SIrina Tirdea if (ret < 0) { 5486da93a67SIrina Tirdea dev_err(&data->client->dev, "powering off device failed\n"); 5496da93a67SIrina Tirdea return -EAGAIN; 5506da93a67SIrina Tirdea } 5516da93a67SIrina Tirdea 5526da93a67SIrina Tirdea return 0; 5536da93a67SIrina Tirdea } 5546da93a67SIrina Tirdea 5556da93a67SIrina Tirdea static int mma9551_runtime_resume(struct device *dev) 5566da93a67SIrina Tirdea { 5576da93a67SIrina Tirdea struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 5586da93a67SIrina Tirdea struct mma9551_data *data = iio_priv(indio_dev); 5596da93a67SIrina Tirdea int ret; 5606da93a67SIrina Tirdea 5616da93a67SIrina Tirdea ret = mma9551_set_device_state(data->client, true); 5626da93a67SIrina Tirdea if (ret < 0) 5636da93a67SIrina Tirdea return ret; 5646da93a67SIrina Tirdea 5656da93a67SIrina Tirdea mma9551_sleep(MMA9551_DEFAULT_SAMPLE_RATE); 5666da93a67SIrina Tirdea 5676da93a67SIrina Tirdea return 0; 5686da93a67SIrina Tirdea } 5696da93a67SIrina Tirdea #endif 5706da93a67SIrina Tirdea 571c78b9171SVlad Dogaru #ifdef CONFIG_PM_SLEEP 572c78b9171SVlad Dogaru static int mma9551_suspend(struct device *dev) 573c78b9171SVlad Dogaru { 574c78b9171SVlad Dogaru struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 575c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 5766da93a67SIrina Tirdea int ret; 577c78b9171SVlad Dogaru 578c78b9171SVlad Dogaru mutex_lock(&data->mutex); 5796da93a67SIrina Tirdea ret = mma9551_set_device_state(data->client, false); 580c78b9171SVlad Dogaru mutex_unlock(&data->mutex); 581c78b9171SVlad Dogaru 5826da93a67SIrina Tirdea return ret; 583c78b9171SVlad Dogaru } 584c78b9171SVlad Dogaru 585c78b9171SVlad Dogaru static int mma9551_resume(struct device *dev) 586c78b9171SVlad Dogaru { 587c78b9171SVlad Dogaru struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 588c78b9171SVlad Dogaru struct mma9551_data *data = iio_priv(indio_dev); 5896da93a67SIrina Tirdea int ret; 590c78b9171SVlad Dogaru 591c78b9171SVlad Dogaru mutex_lock(&data->mutex); 5926da93a67SIrina Tirdea ret = mma9551_set_device_state(data->client, true); 593c78b9171SVlad Dogaru mutex_unlock(&data->mutex); 594c78b9171SVlad Dogaru 5956da93a67SIrina Tirdea return ret; 596c78b9171SVlad Dogaru } 597c78b9171SVlad Dogaru #endif 598c78b9171SVlad Dogaru 599c78b9171SVlad Dogaru static const struct dev_pm_ops mma9551_pm_ops = { 600c78b9171SVlad Dogaru SET_SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume) 6016da93a67SIrina Tirdea SET_RUNTIME_PM_OPS(mma9551_runtime_suspend, 6026da93a67SIrina Tirdea mma9551_runtime_resume, NULL) 603c78b9171SVlad Dogaru }; 604c78b9171SVlad Dogaru 605c78b9171SVlad Dogaru static const struct acpi_device_id mma9551_acpi_match[] = { 606c78b9171SVlad Dogaru {"MMA9551", 0}, 607c78b9171SVlad Dogaru {}, 608c78b9171SVlad Dogaru }; 609c78b9171SVlad Dogaru 610c78b9171SVlad Dogaru MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match); 611c78b9171SVlad Dogaru 612c78b9171SVlad Dogaru static const struct i2c_device_id mma9551_id[] = { 613c78b9171SVlad Dogaru {"mma9551", 0}, 614c78b9171SVlad Dogaru {} 615c78b9171SVlad Dogaru }; 616c78b9171SVlad Dogaru 617c78b9171SVlad Dogaru MODULE_DEVICE_TABLE(i2c, mma9551_id); 618c78b9171SVlad Dogaru 619c78b9171SVlad Dogaru static struct i2c_driver mma9551_driver = { 620c78b9171SVlad Dogaru .driver = { 621c78b9171SVlad Dogaru .name = MMA9551_DRV_NAME, 622c78b9171SVlad Dogaru .acpi_match_table = ACPI_PTR(mma9551_acpi_match), 623c78b9171SVlad Dogaru .pm = &mma9551_pm_ops, 624c78b9171SVlad Dogaru }, 625c78b9171SVlad Dogaru .probe = mma9551_probe, 626c78b9171SVlad Dogaru .remove = mma9551_remove, 627c78b9171SVlad Dogaru .id_table = mma9551_id, 628c78b9171SVlad Dogaru }; 629c78b9171SVlad Dogaru 630c78b9171SVlad Dogaru module_i2c_driver(mma9551_driver); 631c78b9171SVlad Dogaru 632c78b9171SVlad Dogaru MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); 633c78b9171SVlad Dogaru MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>"); 634c78b9171SVlad Dogaru MODULE_LICENSE("GPL v2"); 635c78b9171SVlad Dogaru MODULE_DESCRIPTION("MMA9551L motion-sensing platform driver"); 636