Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Freescale MMA7660FC 3-Axis Accelerometer
0004  *
0005  * Copyright (c) 2016, Intel Corporation.
0006  *
0007  * IIO driver for Freescale MMA7660FC; 7-bit I2C address: 0x4c.
0008  */
0009 
0010 #include <linux/i2c.h>
0011 #include <linux/mod_devicetable.h>
0012 #include <linux/module.h>
0013 #include <linux/iio/iio.h>
0014 #include <linux/iio/sysfs.h>
0015 
0016 #define MMA7660_DRIVER_NAME "mma7660"
0017 
0018 #define MMA7660_REG_XOUT    0x00
0019 #define MMA7660_REG_YOUT    0x01
0020 #define MMA7660_REG_ZOUT    0x02
0021 #define MMA7660_REG_OUT_BIT_ALERT   BIT(6)
0022 
0023 #define MMA7660_REG_MODE    0x07
0024 #define MMA7660_REG_MODE_BIT_MODE   BIT(0)
0025 #define MMA7660_REG_MODE_BIT_TON    BIT(2)
0026 
0027 #define MMA7660_I2C_READ_RETRIES    5
0028 
0029 /*
0030  * The accelerometer has one measurement range:
0031  *
0032  * -1.5g - +1.5g (6-bit, signed)
0033  *
0034  * scale = (1.5 + 1.5) * 9.81 / (2^6 - 1)   = 0.467142857
0035  */
0036 
0037 #define MMA7660_SCALE_AVAIL "0.467142857"
0038 
0039 static const int mma7660_nscale = 467142857;
0040 
0041 #define MMA7660_CHANNEL(reg, axis) {    \
0042     .type = IIO_ACCEL,  \
0043     .address = reg, \
0044     .modified = 1,  \
0045     .channel2 = IIO_MOD_##axis, \
0046     .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
0047     .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
0048 }
0049 
0050 static const struct iio_chan_spec mma7660_channels[] = {
0051     MMA7660_CHANNEL(MMA7660_REG_XOUT, X),
0052     MMA7660_CHANNEL(MMA7660_REG_YOUT, Y),
0053     MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z),
0054 };
0055 
0056 enum mma7660_mode {
0057     MMA7660_MODE_STANDBY,
0058     MMA7660_MODE_ACTIVE
0059 };
0060 
0061 struct mma7660_data {
0062     struct i2c_client *client;
0063     struct mutex lock;
0064     enum mma7660_mode mode;
0065 };
0066 
0067 static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL);
0068 
0069 static struct attribute *mma7660_attributes[] = {
0070     &iio_const_attr_in_accel_scale_available.dev_attr.attr,
0071     NULL,
0072 };
0073 
0074 static const struct attribute_group mma7660_attribute_group = {
0075     .attrs = mma7660_attributes
0076 };
0077 
0078 static int mma7660_set_mode(struct mma7660_data *data,
0079                 enum mma7660_mode mode)
0080 {
0081     int ret;
0082     struct i2c_client *client = data->client;
0083 
0084     if (mode == data->mode)
0085         return 0;
0086 
0087     ret = i2c_smbus_read_byte_data(client, MMA7660_REG_MODE);
0088     if (ret < 0) {
0089         dev_err(&client->dev, "failed to read sensor mode\n");
0090         return ret;
0091     }
0092 
0093     if (mode == MMA7660_MODE_ACTIVE) {
0094         ret &= ~MMA7660_REG_MODE_BIT_TON;
0095         ret |= MMA7660_REG_MODE_BIT_MODE;
0096     } else {
0097         ret &= ~MMA7660_REG_MODE_BIT_TON;
0098         ret &= ~MMA7660_REG_MODE_BIT_MODE;
0099     }
0100 
0101     ret = i2c_smbus_write_byte_data(client, MMA7660_REG_MODE, ret);
0102     if (ret < 0) {
0103         dev_err(&client->dev, "failed to change sensor mode\n");
0104         return ret;
0105     }
0106 
0107     data->mode = mode;
0108 
0109     return ret;
0110 }
0111 
0112 static int mma7660_read_accel(struct mma7660_data *data, u8 address)
0113 {
0114     int ret, retries = MMA7660_I2C_READ_RETRIES;
0115     struct i2c_client *client = data->client;
0116 
0117     /*
0118      * Read data. If the Alert bit is set, the register was read at
0119      * the same time as the device was attempting to update the content.
0120      * The solution is to read the register again. Do this only
0121      * MMA7660_I2C_READ_RETRIES times to avoid spending too much time
0122      * in the kernel.
0123      */
0124     do {
0125         ret = i2c_smbus_read_byte_data(client, address);
0126         if (ret < 0) {
0127             dev_err(&client->dev, "register read failed\n");
0128             return ret;
0129         }
0130     } while (retries-- > 0 && ret & MMA7660_REG_OUT_BIT_ALERT);
0131 
0132     if (ret & MMA7660_REG_OUT_BIT_ALERT) {
0133         dev_err(&client->dev, "all register read retries failed\n");
0134         return -ETIMEDOUT;
0135     }
0136 
0137     return ret;
0138 }
0139 
0140 static int mma7660_read_raw(struct iio_dev *indio_dev,
0141                 struct iio_chan_spec const *chan,
0142                 int *val, int *val2, long mask)
0143 {
0144     struct mma7660_data *data = iio_priv(indio_dev);
0145     int ret;
0146 
0147     switch (mask) {
0148     case IIO_CHAN_INFO_RAW:
0149         mutex_lock(&data->lock);
0150         ret = mma7660_read_accel(data, chan->address);
0151         mutex_unlock(&data->lock);
0152         if (ret < 0)
0153             return ret;
0154         *val = sign_extend32(ret, 5);
0155         return IIO_VAL_INT;
0156     case IIO_CHAN_INFO_SCALE:
0157         *val = 0;
0158         *val2 = mma7660_nscale;
0159         return IIO_VAL_INT_PLUS_NANO;
0160     default:
0161         return -EINVAL;
0162     }
0163 
0164     return -EINVAL;
0165 }
0166 
0167 static const struct iio_info mma7660_info = {
0168     .read_raw       = mma7660_read_raw,
0169     .attrs          = &mma7660_attribute_group,
0170 };
0171 
0172 static int mma7660_probe(struct i2c_client *client,
0173             const struct i2c_device_id *id)
0174 {
0175     int ret;
0176     struct iio_dev *indio_dev;
0177     struct mma7660_data *data;
0178 
0179     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0180     if (!indio_dev) {
0181         dev_err(&client->dev, "iio allocation failed!\n");
0182         return -ENOMEM;
0183     }
0184 
0185     data = iio_priv(indio_dev);
0186     data->client = client;
0187     i2c_set_clientdata(client, indio_dev);
0188     mutex_init(&data->lock);
0189     data->mode = MMA7660_MODE_STANDBY;
0190 
0191     indio_dev->info = &mma7660_info;
0192     indio_dev->name = MMA7660_DRIVER_NAME;
0193     indio_dev->modes = INDIO_DIRECT_MODE;
0194     indio_dev->channels = mma7660_channels;
0195     indio_dev->num_channels = ARRAY_SIZE(mma7660_channels);
0196 
0197     ret = mma7660_set_mode(data, MMA7660_MODE_ACTIVE);
0198     if (ret < 0)
0199         return ret;
0200 
0201     ret = iio_device_register(indio_dev);
0202     if (ret < 0) {
0203         dev_err(&client->dev, "device_register failed\n");
0204         mma7660_set_mode(data, MMA7660_MODE_STANDBY);
0205     }
0206 
0207     return ret;
0208 }
0209 
0210 static int mma7660_remove(struct i2c_client *client)
0211 {
0212     struct iio_dev *indio_dev = i2c_get_clientdata(client);
0213     int ret;
0214 
0215     iio_device_unregister(indio_dev);
0216 
0217     ret = mma7660_set_mode(iio_priv(indio_dev), MMA7660_MODE_STANDBY);
0218     if (ret)
0219         dev_warn(&client->dev, "Failed to put device in stand-by mode (%pe), ignoring\n",
0220              ERR_PTR(ret));
0221 
0222     return 0;
0223 }
0224 
0225 static int mma7660_suspend(struct device *dev)
0226 {
0227     struct mma7660_data *data;
0228 
0229     data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
0230 
0231     return mma7660_set_mode(data, MMA7660_MODE_STANDBY);
0232 }
0233 
0234 static int mma7660_resume(struct device *dev)
0235 {
0236     struct mma7660_data *data;
0237 
0238     data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
0239 
0240     return mma7660_set_mode(data, MMA7660_MODE_ACTIVE);
0241 }
0242 
0243 static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend,
0244                 mma7660_resume);
0245 
0246 static const struct i2c_device_id mma7660_i2c_id[] = {
0247     {"mma7660", 0},
0248     {}
0249 };
0250 MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id);
0251 
0252 static const struct of_device_id mma7660_of_match[] = {
0253     { .compatible = "fsl,mma7660" },
0254     { }
0255 };
0256 MODULE_DEVICE_TABLE(of, mma7660_of_match);
0257 
0258 static const struct acpi_device_id mma7660_acpi_id[] = {
0259     {"MMA7660", 0},
0260     {}
0261 };
0262 
0263 MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id);
0264 
0265 static struct i2c_driver mma7660_driver = {
0266     .driver = {
0267         .name = "mma7660",
0268         .pm = pm_sleep_ptr(&mma7660_pm_ops),
0269         .of_match_table = mma7660_of_match,
0270         .acpi_match_table = mma7660_acpi_id,
0271     },
0272     .probe      = mma7660_probe,
0273     .remove     = mma7660_remove,
0274     .id_table   = mma7660_i2c_id,
0275 };
0276 
0277 module_i2c_driver(mma7660_driver);
0278 
0279 MODULE_AUTHOR("Constantin Musca <constantin.musca@intel.com>");
0280 MODULE_DESCRIPTION("Freescale MMA7660FC 3-Axis Accelerometer driver");
0281 MODULE_LICENSE("GPL v2");