136edc939SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2b9d453a5SGwendal Grignou /* 332133be6SConstantin Musca * Freescale MMA7660FC 3-Axis Accelerometer 432133be6SConstantin Musca * 532133be6SConstantin Musca * Copyright (c) 2016, Intel Corporation. 632133be6SConstantin Musca * 732133be6SConstantin Musca * IIO driver for Freescale MMA7660FC; 7-bit I2C address: 0x4c. 832133be6SConstantin Musca */ 932133be6SConstantin Musca 1032133be6SConstantin Musca #include <linux/acpi.h> 1132133be6SConstantin Musca #include <linux/i2c.h> 1232133be6SConstantin Musca #include <linux/module.h> 1332133be6SConstantin Musca #include <linux/iio/iio.h> 1432133be6SConstantin Musca #include <linux/iio/sysfs.h> 1532133be6SConstantin Musca 1632133be6SConstantin Musca #define MMA7660_DRIVER_NAME "mma7660" 1732133be6SConstantin Musca 1832133be6SConstantin Musca #define MMA7660_REG_XOUT 0x00 1932133be6SConstantin Musca #define MMA7660_REG_YOUT 0x01 2032133be6SConstantin Musca #define MMA7660_REG_ZOUT 0x02 2132133be6SConstantin Musca #define MMA7660_REG_OUT_BIT_ALERT BIT(6) 2232133be6SConstantin Musca 2332133be6SConstantin Musca #define MMA7660_REG_MODE 0x07 2432133be6SConstantin Musca #define MMA7660_REG_MODE_BIT_MODE BIT(0) 2532133be6SConstantin Musca #define MMA7660_REG_MODE_BIT_TON BIT(2) 2632133be6SConstantin Musca 2732133be6SConstantin Musca #define MMA7660_I2C_READ_RETRIES 5 2832133be6SConstantin Musca 2932133be6SConstantin Musca /* 3032133be6SConstantin Musca * The accelerometer has one measurement range: 3132133be6SConstantin Musca * 3232133be6SConstantin Musca * -1.5g - +1.5g (6-bit, signed) 3332133be6SConstantin Musca * 3432133be6SConstantin Musca * scale = (1.5 + 1.5) * 9.81 / (2^6 - 1) = 0.467142857 3532133be6SConstantin Musca */ 3632133be6SConstantin Musca 3732133be6SConstantin Musca #define MMA7660_SCALE_AVAIL "0.467142857" 3832133be6SConstantin Musca 391b14adcaSWei Yongjun static const int mma7660_nscale = 467142857; 4032133be6SConstantin Musca 4132133be6SConstantin Musca #define MMA7660_CHANNEL(reg, axis) { \ 4232133be6SConstantin Musca .type = IIO_ACCEL, \ 4332133be6SConstantin Musca .address = reg, \ 4432133be6SConstantin Musca .modified = 1, \ 4532133be6SConstantin Musca .channel2 = IIO_MOD_##axis, \ 4632133be6SConstantin Musca .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 4732133be6SConstantin Musca .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 4832133be6SConstantin Musca } 4932133be6SConstantin Musca 5032133be6SConstantin Musca static const struct iio_chan_spec mma7660_channels[] = { 5132133be6SConstantin Musca MMA7660_CHANNEL(MMA7660_REG_XOUT, X), 5232133be6SConstantin Musca MMA7660_CHANNEL(MMA7660_REG_YOUT, Y), 5332133be6SConstantin Musca MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z), 5432133be6SConstantin Musca }; 5532133be6SConstantin Musca 5632133be6SConstantin Musca enum mma7660_mode { 5732133be6SConstantin Musca MMA7660_MODE_STANDBY, 5832133be6SConstantin Musca MMA7660_MODE_ACTIVE 5932133be6SConstantin Musca }; 6032133be6SConstantin Musca 6132133be6SConstantin Musca struct mma7660_data { 6232133be6SConstantin Musca struct i2c_client *client; 6332133be6SConstantin Musca struct mutex lock; 6432133be6SConstantin Musca enum mma7660_mode mode; 6532133be6SConstantin Musca }; 6632133be6SConstantin Musca 6732133be6SConstantin Musca static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL); 6832133be6SConstantin Musca 6932133be6SConstantin Musca static struct attribute *mma7660_attributes[] = { 7032133be6SConstantin Musca &iio_const_attr_in_accel_scale_available.dev_attr.attr, 7132133be6SConstantin Musca NULL, 7232133be6SConstantin Musca }; 7332133be6SConstantin Musca 7432133be6SConstantin Musca static const struct attribute_group mma7660_attribute_group = { 7532133be6SConstantin Musca .attrs = mma7660_attributes 7632133be6SConstantin Musca }; 7732133be6SConstantin Musca 7832133be6SConstantin Musca static int mma7660_set_mode(struct mma7660_data *data, 7932133be6SConstantin Musca enum mma7660_mode mode) 8032133be6SConstantin Musca { 8132133be6SConstantin Musca int ret; 8232133be6SConstantin Musca struct i2c_client *client = data->client; 8332133be6SConstantin Musca 8432133be6SConstantin Musca if (mode == data->mode) 8532133be6SConstantin Musca return 0; 8632133be6SConstantin Musca 8732133be6SConstantin Musca ret = i2c_smbus_read_byte_data(client, MMA7660_REG_MODE); 8832133be6SConstantin Musca if (ret < 0) { 8932133be6SConstantin Musca dev_err(&client->dev, "failed to read sensor mode\n"); 9032133be6SConstantin Musca return ret; 9132133be6SConstantin Musca } 9232133be6SConstantin Musca 9332133be6SConstantin Musca if (mode == MMA7660_MODE_ACTIVE) { 9432133be6SConstantin Musca ret &= ~MMA7660_REG_MODE_BIT_TON; 9532133be6SConstantin Musca ret |= MMA7660_REG_MODE_BIT_MODE; 9632133be6SConstantin Musca } else { 9732133be6SConstantin Musca ret &= ~MMA7660_REG_MODE_BIT_TON; 9832133be6SConstantin Musca ret &= ~MMA7660_REG_MODE_BIT_MODE; 9932133be6SConstantin Musca } 10032133be6SConstantin Musca 10132133be6SConstantin Musca ret = i2c_smbus_write_byte_data(client, MMA7660_REG_MODE, ret); 10232133be6SConstantin Musca if (ret < 0) { 10332133be6SConstantin Musca dev_err(&client->dev, "failed to change sensor mode\n"); 10432133be6SConstantin Musca return ret; 10532133be6SConstantin Musca } 10632133be6SConstantin Musca 10732133be6SConstantin Musca data->mode = mode; 10832133be6SConstantin Musca 10932133be6SConstantin Musca return ret; 11032133be6SConstantin Musca } 11132133be6SConstantin Musca 11232133be6SConstantin Musca static int mma7660_read_accel(struct mma7660_data *data, u8 address) 11332133be6SConstantin Musca { 11432133be6SConstantin Musca int ret, retries = MMA7660_I2C_READ_RETRIES; 11532133be6SConstantin Musca struct i2c_client *client = data->client; 11632133be6SConstantin Musca 11732133be6SConstantin Musca /* 11832133be6SConstantin Musca * Read data. If the Alert bit is set, the register was read at 11932133be6SConstantin Musca * the same time as the device was attempting to update the content. 12032133be6SConstantin Musca * The solution is to read the register again. Do this only 12132133be6SConstantin Musca * MMA7660_I2C_READ_RETRIES times to avoid spending too much time 12232133be6SConstantin Musca * in the kernel. 12332133be6SConstantin Musca */ 12432133be6SConstantin Musca do { 12532133be6SConstantin Musca ret = i2c_smbus_read_byte_data(client, address); 12632133be6SConstantin Musca if (ret < 0) { 12732133be6SConstantin Musca dev_err(&client->dev, "register read failed\n"); 12832133be6SConstantin Musca return ret; 12932133be6SConstantin Musca } 13032133be6SConstantin Musca } while (retries-- > 0 && ret & MMA7660_REG_OUT_BIT_ALERT); 13132133be6SConstantin Musca 13232133be6SConstantin Musca if (ret & MMA7660_REG_OUT_BIT_ALERT) { 13332133be6SConstantin Musca dev_err(&client->dev, "all register read retries failed\n"); 13432133be6SConstantin Musca return -ETIMEDOUT; 13532133be6SConstantin Musca } 13632133be6SConstantin Musca 13732133be6SConstantin Musca return ret; 13832133be6SConstantin Musca } 13932133be6SConstantin Musca 14032133be6SConstantin Musca static int mma7660_read_raw(struct iio_dev *indio_dev, 14132133be6SConstantin Musca struct iio_chan_spec const *chan, 14232133be6SConstantin Musca int *val, int *val2, long mask) 14332133be6SConstantin Musca { 14432133be6SConstantin Musca struct mma7660_data *data = iio_priv(indio_dev); 14532133be6SConstantin Musca int ret; 14632133be6SConstantin Musca 14732133be6SConstantin Musca switch (mask) { 14832133be6SConstantin Musca case IIO_CHAN_INFO_RAW: 14932133be6SConstantin Musca mutex_lock(&data->lock); 15032133be6SConstantin Musca ret = mma7660_read_accel(data, chan->address); 15132133be6SConstantin Musca mutex_unlock(&data->lock); 15232133be6SConstantin Musca if (ret < 0) 15332133be6SConstantin Musca return ret; 15432133be6SConstantin Musca *val = sign_extend32(ret, 5); 15532133be6SConstantin Musca return IIO_VAL_INT; 15632133be6SConstantin Musca case IIO_CHAN_INFO_SCALE: 15732133be6SConstantin Musca *val = 0; 15832133be6SConstantin Musca *val2 = mma7660_nscale; 15932133be6SConstantin Musca return IIO_VAL_INT_PLUS_NANO; 16032133be6SConstantin Musca default: 16132133be6SConstantin Musca return -EINVAL; 16232133be6SConstantin Musca } 16332133be6SConstantin Musca 16432133be6SConstantin Musca return -EINVAL; 16532133be6SConstantin Musca } 16632133be6SConstantin Musca 16732133be6SConstantin Musca static const struct iio_info mma7660_info = { 16832133be6SConstantin Musca .read_raw = mma7660_read_raw, 16932133be6SConstantin Musca .attrs = &mma7660_attribute_group, 17032133be6SConstantin Musca }; 17132133be6SConstantin Musca 17232133be6SConstantin Musca static int mma7660_probe(struct i2c_client *client, 17332133be6SConstantin Musca const struct i2c_device_id *id) 17432133be6SConstantin Musca { 17532133be6SConstantin Musca int ret; 17632133be6SConstantin Musca struct iio_dev *indio_dev; 17732133be6SConstantin Musca struct mma7660_data *data; 17832133be6SConstantin Musca 17932133be6SConstantin Musca indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 18032133be6SConstantin Musca if (!indio_dev) { 18132133be6SConstantin Musca dev_err(&client->dev, "iio allocation failed!\n"); 18232133be6SConstantin Musca return -ENOMEM; 18332133be6SConstantin Musca } 18432133be6SConstantin Musca 18532133be6SConstantin Musca data = iio_priv(indio_dev); 18632133be6SConstantin Musca data->client = client; 18732133be6SConstantin Musca i2c_set_clientdata(client, indio_dev); 18832133be6SConstantin Musca mutex_init(&data->lock); 18932133be6SConstantin Musca data->mode = MMA7660_MODE_STANDBY; 19032133be6SConstantin Musca 19132133be6SConstantin Musca indio_dev->info = &mma7660_info; 19232133be6SConstantin Musca indio_dev->name = MMA7660_DRIVER_NAME; 19332133be6SConstantin Musca indio_dev->modes = INDIO_DIRECT_MODE; 19432133be6SConstantin Musca indio_dev->channels = mma7660_channels; 19532133be6SConstantin Musca indio_dev->num_channels = ARRAY_SIZE(mma7660_channels); 19632133be6SConstantin Musca 19732133be6SConstantin Musca ret = mma7660_set_mode(data, MMA7660_MODE_ACTIVE); 19832133be6SConstantin Musca if (ret < 0) 19932133be6SConstantin Musca return ret; 20032133be6SConstantin Musca 20132133be6SConstantin Musca ret = iio_device_register(indio_dev); 20232133be6SConstantin Musca if (ret < 0) { 20332133be6SConstantin Musca dev_err(&client->dev, "device_register failed\n"); 20432133be6SConstantin Musca mma7660_set_mode(data, MMA7660_MODE_STANDBY); 20532133be6SConstantin Musca } 20632133be6SConstantin Musca 20732133be6SConstantin Musca return ret; 20832133be6SConstantin Musca } 20932133be6SConstantin Musca 21032133be6SConstantin Musca static int mma7660_remove(struct i2c_client *client) 21132133be6SConstantin Musca { 21232133be6SConstantin Musca struct iio_dev *indio_dev = i2c_get_clientdata(client); 213e12653ebSUwe Kleine-König int ret; 21432133be6SConstantin Musca 21532133be6SConstantin Musca iio_device_unregister(indio_dev); 21632133be6SConstantin Musca 217e12653ebSUwe Kleine-König ret = mma7660_set_mode(iio_priv(indio_dev), MMA7660_MODE_STANDBY); 218e12653ebSUwe Kleine-König if (ret) 219e12653ebSUwe Kleine-König dev_warn(&client->dev, "Failed to put device in stand-by mode (%pe), ignoring\n", 220e12653ebSUwe Kleine-König ERR_PTR(ret)); 221e12653ebSUwe Kleine-König 222e12653ebSUwe Kleine-König return 0; 22332133be6SConstantin Musca } 22432133be6SConstantin Musca 22532133be6SConstantin Musca static int mma7660_suspend(struct device *dev) 22632133be6SConstantin Musca { 22732133be6SConstantin Musca struct mma7660_data *data; 22832133be6SConstantin Musca 22932133be6SConstantin Musca data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); 23032133be6SConstantin Musca 23132133be6SConstantin Musca return mma7660_set_mode(data, MMA7660_MODE_STANDBY); 23232133be6SConstantin Musca } 23332133be6SConstantin Musca 23432133be6SConstantin Musca static int mma7660_resume(struct device *dev) 23532133be6SConstantin Musca { 23632133be6SConstantin Musca struct mma7660_data *data; 23732133be6SConstantin Musca 23832133be6SConstantin Musca data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); 23932133be6SConstantin Musca 24032133be6SConstantin Musca return mma7660_set_mode(data, MMA7660_MODE_ACTIVE); 24132133be6SConstantin Musca } 24232133be6SConstantin Musca 243*812c5f31SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, 244*812c5f31SJonathan Cameron mma7660_resume); 24532133be6SConstantin Musca 24632133be6SConstantin Musca static const struct i2c_device_id mma7660_i2c_id[] = { 24732133be6SConstantin Musca {"mma7660", 0}, 24832133be6SConstantin Musca {} 24932133be6SConstantin Musca }; 25056203188SHans de Goede MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id); 25132133be6SConstantin Musca 252f1c088a7SJavier Martinez Canillas static const struct of_device_id mma7660_of_match[] = { 253f1c088a7SJavier Martinez Canillas { .compatible = "fsl,mma7660" }, 254f1c088a7SJavier Martinez Canillas { } 255f1c088a7SJavier Martinez Canillas }; 256f1c088a7SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, mma7660_of_match); 257f1c088a7SJavier Martinez Canillas 2580fe14020SDaniel Palmer static const struct acpi_device_id __maybe_unused mma7660_acpi_id[] = { 25932133be6SConstantin Musca {"MMA7660", 0}, 26032133be6SConstantin Musca {} 26132133be6SConstantin Musca }; 26232133be6SConstantin Musca 26332133be6SConstantin Musca MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id); 26432133be6SConstantin Musca 26532133be6SConstantin Musca static struct i2c_driver mma7660_driver = { 26632133be6SConstantin Musca .driver = { 26732133be6SConstantin Musca .name = "mma7660", 268*812c5f31SJonathan Cameron .pm = pm_sleep_ptr(&mma7660_pm_ops), 269f1c088a7SJavier Martinez Canillas .of_match_table = mma7660_of_match, 27032133be6SConstantin Musca .acpi_match_table = ACPI_PTR(mma7660_acpi_id), 27132133be6SConstantin Musca }, 27232133be6SConstantin Musca .probe = mma7660_probe, 27332133be6SConstantin Musca .remove = mma7660_remove, 27432133be6SConstantin Musca .id_table = mma7660_i2c_id, 27532133be6SConstantin Musca }; 27632133be6SConstantin Musca 27732133be6SConstantin Musca module_i2c_driver(mma7660_driver); 27832133be6SConstantin Musca 27932133be6SConstantin Musca MODULE_AUTHOR("Constantin Musca <constantin.musca@intel.com>"); 28032133be6SConstantin Musca MODULE_DESCRIPTION("Freescale MMA7660FC 3-Axis Accelerometer driver"); 28132133be6SConstantin Musca MODULE_LICENSE("GPL v2"); 282