Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * IIO accel core driver for Freescale MMA7455L 3-axis 10-bit accelerometer
0004  * Copyright 2015 Joachim Eastwood <manabian@gmail.com>
0005  *
0006  * UNSUPPORTED hardware features:
0007  *  - 8-bit mode with different scales
0008  *  - INT1/INT2 interrupts
0009  *  - Offset calibration
0010  *  - Events
0011  */
0012 
0013 #include <linux/delay.h>
0014 #include <linux/iio/iio.h>
0015 #include <linux/iio/sysfs.h>
0016 #include <linux/iio/buffer.h>
0017 #include <linux/iio/trigger.h>
0018 #include <linux/iio/trigger_consumer.h>
0019 #include <linux/iio/triggered_buffer.h>
0020 #include <linux/module.h>
0021 #include <linux/regmap.h>
0022 
0023 #include "mma7455.h"
0024 
0025 #define MMA7455_REG_XOUTL       0x00
0026 #define MMA7455_REG_XOUTH       0x01
0027 #define MMA7455_REG_YOUTL       0x02
0028 #define MMA7455_REG_YOUTH       0x03
0029 #define MMA7455_REG_ZOUTL       0x04
0030 #define MMA7455_REG_ZOUTH       0x05
0031 #define MMA7455_REG_STATUS      0x09
0032 #define  MMA7455_STATUS_DRDY        BIT(0)
0033 #define MMA7455_REG_WHOAMI      0x0f
0034 #define  MMA7455_WHOAMI_ID      0x55
0035 #define MMA7455_REG_MCTL        0x16
0036 #define  MMA7455_MCTL_MODE_STANDBY  0x00
0037 #define  MMA7455_MCTL_MODE_MEASURE  0x01
0038 #define MMA7455_REG_CTL1        0x18
0039 #define  MMA7455_CTL1_DFBW_MASK     BIT(7)
0040 #define  MMA7455_CTL1_DFBW_125HZ    BIT(7)
0041 #define  MMA7455_CTL1_DFBW_62_5HZ   0
0042 #define MMA7455_REG_TW          0x1e
0043 
0044 /*
0045  * When MMA7455 is used in 10-bit it has a fullscale of -8g
0046  * corresponding to raw value -512. The userspace interface
0047  * uses m/s^2 and we declare micro units.
0048  * So scale factor is given by:
0049  *       g * 8 * 1e6 / 512 = 153228.90625, with g = 9.80665
0050  */
0051 #define MMA7455_10BIT_SCALE 153229
0052 
0053 struct mma7455_data {
0054     struct regmap *regmap;
0055     /*
0056      * Used to reorganize data.  Will ensure correct alignment of
0057      * the timestamp if present
0058      */
0059     struct {
0060         __le16 channels[3];
0061         s64 ts __aligned(8);
0062     } scan;
0063 };
0064 
0065 static int mma7455_drdy(struct mma7455_data *mma7455)
0066 {
0067     struct device *dev = regmap_get_device(mma7455->regmap);
0068     unsigned int reg;
0069     int tries = 3;
0070     int ret;
0071 
0072     while (tries-- > 0) {
0073         ret = regmap_read(mma7455->regmap, MMA7455_REG_STATUS, &reg);
0074         if (ret)
0075             return ret;
0076 
0077         if (reg & MMA7455_STATUS_DRDY)
0078             return 0;
0079 
0080         msleep(20);
0081     }
0082 
0083     dev_warn(dev, "data not ready\n");
0084 
0085     return -EIO;
0086 }
0087 
0088 static irqreturn_t mma7455_trigger_handler(int irq, void *p)
0089 {
0090     struct iio_poll_func *pf = p;
0091     struct iio_dev *indio_dev = pf->indio_dev;
0092     struct mma7455_data *mma7455 = iio_priv(indio_dev);
0093     int ret;
0094 
0095     ret = mma7455_drdy(mma7455);
0096     if (ret)
0097         goto done;
0098 
0099     ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL,
0100                    mma7455->scan.channels,
0101                    sizeof(mma7455->scan.channels));
0102     if (ret)
0103         goto done;
0104 
0105     iio_push_to_buffers_with_timestamp(indio_dev, &mma7455->scan,
0106                        iio_get_time_ns(indio_dev));
0107 
0108 done:
0109     iio_trigger_notify_done(indio_dev->trig);
0110 
0111     return IRQ_HANDLED;
0112 }
0113 
0114 static int mma7455_read_raw(struct iio_dev *indio_dev,
0115                 struct iio_chan_spec const *chan,
0116                 int *val, int *val2, long mask)
0117 {
0118     struct mma7455_data *mma7455 = iio_priv(indio_dev);
0119     unsigned int reg;
0120     __le16 data;
0121     int ret;
0122 
0123     switch (mask) {
0124     case IIO_CHAN_INFO_RAW:
0125         if (iio_buffer_enabled(indio_dev))
0126             return -EBUSY;
0127 
0128         ret = mma7455_drdy(mma7455);
0129         if (ret)
0130             return ret;
0131 
0132         ret = regmap_bulk_read(mma7455->regmap, chan->address, &data,
0133                        sizeof(data));
0134         if (ret)
0135             return ret;
0136 
0137         *val = sign_extend32(le16_to_cpu(data),
0138                      chan->scan_type.realbits - 1);
0139 
0140         return IIO_VAL_INT;
0141 
0142     case IIO_CHAN_INFO_SCALE:
0143         *val = 0;
0144         *val2 = MMA7455_10BIT_SCALE;
0145 
0146         return IIO_VAL_INT_PLUS_MICRO;
0147 
0148     case IIO_CHAN_INFO_SAMP_FREQ:
0149         ret = regmap_read(mma7455->regmap, MMA7455_REG_CTL1, &reg);
0150         if (ret)
0151             return ret;
0152 
0153         if (reg & MMA7455_CTL1_DFBW_MASK)
0154             *val = 250;
0155         else
0156             *val = 125;
0157 
0158         return IIO_VAL_INT;
0159     }
0160 
0161     return -EINVAL;
0162 }
0163 
0164 static int mma7455_write_raw(struct iio_dev *indio_dev,
0165                  struct iio_chan_spec const *chan,
0166                  int val, int val2, long mask)
0167 {
0168     struct mma7455_data *mma7455 = iio_priv(indio_dev);
0169     int i;
0170 
0171     switch (mask) {
0172     case IIO_CHAN_INFO_SAMP_FREQ:
0173         if (val == 250 && val2 == 0)
0174             i = MMA7455_CTL1_DFBW_125HZ;
0175         else if (val == 125 && val2 == 0)
0176             i = MMA7455_CTL1_DFBW_62_5HZ;
0177         else
0178             return -EINVAL;
0179 
0180         return regmap_update_bits(mma7455->regmap, MMA7455_REG_CTL1,
0181                       MMA7455_CTL1_DFBW_MASK, i);
0182 
0183     case IIO_CHAN_INFO_SCALE:
0184         /* In 10-bit mode there is only one scale available */
0185         if (val == 0 && val2 == MMA7455_10BIT_SCALE)
0186             return 0;
0187         break;
0188     }
0189 
0190     return -EINVAL;
0191 }
0192 
0193 static IIO_CONST_ATTR(sampling_frequency_available, "125 250");
0194 
0195 static struct attribute *mma7455_attributes[] = {
0196     &iio_const_attr_sampling_frequency_available.dev_attr.attr,
0197     NULL
0198 };
0199 
0200 static const struct attribute_group mma7455_group = {
0201     .attrs = mma7455_attributes,
0202 };
0203 
0204 static const struct iio_info mma7455_info = {
0205     .attrs = &mma7455_group,
0206     .read_raw = mma7455_read_raw,
0207     .write_raw = mma7455_write_raw,
0208 };
0209 
0210 #define MMA7455_CHANNEL(axis, idx) { \
0211     .type = IIO_ACCEL, \
0212     .modified = 1, \
0213     .address = MMA7455_REG_##axis##OUTL,\
0214     .channel2 = IIO_MOD_##axis, \
0215     .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
0216     .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
0217                     BIT(IIO_CHAN_INFO_SCALE), \
0218     .scan_index = idx, \
0219     .scan_type = { \
0220         .sign = 's', \
0221         .realbits = 10, \
0222         .storagebits = 16, \
0223         .endianness = IIO_LE, \
0224     }, \
0225 }
0226 
0227 static const struct iio_chan_spec mma7455_channels[] = {
0228     MMA7455_CHANNEL(X, 0),
0229     MMA7455_CHANNEL(Y, 1),
0230     MMA7455_CHANNEL(Z, 2),
0231     IIO_CHAN_SOFT_TIMESTAMP(3),
0232 };
0233 
0234 static const unsigned long mma7455_scan_masks[] = {0x7, 0};
0235 
0236 const struct regmap_config mma7455_core_regmap = {
0237     .reg_bits = 8,
0238     .val_bits = 8,
0239     .max_register = MMA7455_REG_TW,
0240 };
0241 EXPORT_SYMBOL_NS_GPL(mma7455_core_regmap, IIO_MMA7455);
0242 
0243 int mma7455_core_probe(struct device *dev, struct regmap *regmap,
0244                const char *name)
0245 {
0246     struct mma7455_data *mma7455;
0247     struct iio_dev *indio_dev;
0248     unsigned int reg;
0249     int ret;
0250 
0251     ret = regmap_read(regmap, MMA7455_REG_WHOAMI, &reg);
0252     if (ret) {
0253         dev_err(dev, "unable to read reg\n");
0254         return ret;
0255     }
0256 
0257     if (reg != MMA7455_WHOAMI_ID) {
0258         dev_err(dev, "device id mismatch\n");
0259         return -ENODEV;
0260     }
0261 
0262     indio_dev = devm_iio_device_alloc(dev, sizeof(*mma7455));
0263     if (!indio_dev)
0264         return -ENOMEM;
0265 
0266     dev_set_drvdata(dev, indio_dev);
0267     mma7455 = iio_priv(indio_dev);
0268     mma7455->regmap = regmap;
0269 
0270     indio_dev->info = &mma7455_info;
0271     indio_dev->name = name;
0272     indio_dev->modes = INDIO_DIRECT_MODE;
0273     indio_dev->channels = mma7455_channels;
0274     indio_dev->num_channels = ARRAY_SIZE(mma7455_channels);
0275     indio_dev->available_scan_masks = mma7455_scan_masks;
0276 
0277     regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
0278              MMA7455_MCTL_MODE_MEASURE);
0279 
0280     ret = iio_triggered_buffer_setup(indio_dev, NULL,
0281                      mma7455_trigger_handler, NULL);
0282     if (ret) {
0283         dev_err(dev, "unable to setup triggered buffer\n");
0284         return ret;
0285     }
0286 
0287     ret = iio_device_register(indio_dev);
0288     if (ret) {
0289         dev_err(dev, "unable to register device\n");
0290         iio_triggered_buffer_cleanup(indio_dev);
0291         return ret;
0292     }
0293 
0294     return 0;
0295 }
0296 EXPORT_SYMBOL_NS_GPL(mma7455_core_probe, IIO_MMA7455);
0297 
0298 void mma7455_core_remove(struct device *dev)
0299 {
0300     struct iio_dev *indio_dev = dev_get_drvdata(dev);
0301     struct mma7455_data *mma7455 = iio_priv(indio_dev);
0302 
0303     iio_device_unregister(indio_dev);
0304     iio_triggered_buffer_cleanup(indio_dev);
0305 
0306     regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
0307              MMA7455_MCTL_MODE_STANDBY);
0308 }
0309 EXPORT_SYMBOL_NS_GPL(mma7455_core_remove, IIO_MMA7455);
0310 
0311 MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
0312 MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver");
0313 MODULE_LICENSE("GPL v2");