1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * IIO accel core driver for Freescale MMA7455L 3-axis 10-bit accelerometer 4 * Copyright 2015 Joachim Eastwood <manabian@gmail.com> 5 * 6 * UNSUPPORTED hardware features: 7 * - 8-bit mode with different scales 8 * - INT1/INT2 interrupts 9 * - Offset calibration 10 * - Events 11 */ 12 13 #include <linux/delay.h> 14 #include <linux/iio/iio.h> 15 #include <linux/iio/sysfs.h> 16 #include <linux/iio/buffer.h> 17 #include <linux/iio/trigger.h> 18 #include <linux/iio/trigger_consumer.h> 19 #include <linux/iio/triggered_buffer.h> 20 #include <linux/module.h> 21 #include <linux/regmap.h> 22 23 #include "mma7455.h" 24 25 #define MMA7455_REG_XOUTL 0x00 26 #define MMA7455_REG_XOUTH 0x01 27 #define MMA7455_REG_YOUTL 0x02 28 #define MMA7455_REG_YOUTH 0x03 29 #define MMA7455_REG_ZOUTL 0x04 30 #define MMA7455_REG_ZOUTH 0x05 31 #define MMA7455_REG_STATUS 0x09 32 #define MMA7455_STATUS_DRDY BIT(0) 33 #define MMA7455_REG_WHOAMI 0x0f 34 #define MMA7455_WHOAMI_ID 0x55 35 #define MMA7455_REG_MCTL 0x16 36 #define MMA7455_MCTL_MODE_STANDBY 0x00 37 #define MMA7455_MCTL_MODE_MEASURE 0x01 38 #define MMA7455_REG_CTL1 0x18 39 #define MMA7455_CTL1_DFBW_MASK BIT(7) 40 #define MMA7455_CTL1_DFBW_125HZ BIT(7) 41 #define MMA7455_CTL1_DFBW_62_5HZ 0 42 #define MMA7455_REG_TW 0x1e 43 44 /* 45 * When MMA7455 is used in 10-bit it has a fullscale of -8g 46 * corresponding to raw value -512. The userspace interface 47 * uses m/s^2 and we declare micro units. 48 * So scale factor is given by: 49 * g * 8 * 1e6 / 512 = 153228.90625, with g = 9.80665 50 */ 51 #define MMA7455_10BIT_SCALE 153229 52 53 struct mma7455_data { 54 struct regmap *regmap; 55 }; 56 57 static int mma7455_drdy(struct mma7455_data *mma7455) 58 { 59 struct device *dev = regmap_get_device(mma7455->regmap); 60 unsigned int reg; 61 int tries = 3; 62 int ret; 63 64 while (tries-- > 0) { 65 ret = regmap_read(mma7455->regmap, MMA7455_REG_STATUS, ®); 66 if (ret) 67 return ret; 68 69 if (reg & MMA7455_STATUS_DRDY) 70 return 0; 71 72 msleep(20); 73 } 74 75 dev_warn(dev, "data not ready\n"); 76 77 return -EIO; 78 } 79 80 static irqreturn_t mma7455_trigger_handler(int irq, void *p) 81 { 82 struct iio_poll_func *pf = p; 83 struct iio_dev *indio_dev = pf->indio_dev; 84 struct mma7455_data *mma7455 = iio_priv(indio_dev); 85 u8 buf[16]; /* 3 x 16-bit channels + padding + ts */ 86 int ret; 87 88 ret = mma7455_drdy(mma7455); 89 if (ret) 90 goto done; 91 92 ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL, buf, 93 sizeof(__le16) * 3); 94 if (ret) 95 goto done; 96 97 iio_push_to_buffers_with_timestamp(indio_dev, buf, 98 iio_get_time_ns(indio_dev)); 99 100 done: 101 iio_trigger_notify_done(indio_dev->trig); 102 103 return IRQ_HANDLED; 104 } 105 106 static int mma7455_read_raw(struct iio_dev *indio_dev, 107 struct iio_chan_spec const *chan, 108 int *val, int *val2, long mask) 109 { 110 struct mma7455_data *mma7455 = iio_priv(indio_dev); 111 unsigned int reg; 112 __le16 data; 113 int ret; 114 115 switch (mask) { 116 case IIO_CHAN_INFO_RAW: 117 if (iio_buffer_enabled(indio_dev)) 118 return -EBUSY; 119 120 ret = mma7455_drdy(mma7455); 121 if (ret) 122 return ret; 123 124 ret = regmap_bulk_read(mma7455->regmap, chan->address, &data, 125 sizeof(data)); 126 if (ret) 127 return ret; 128 129 *val = sign_extend32(le16_to_cpu(data), 9); 130 131 return IIO_VAL_INT; 132 133 case IIO_CHAN_INFO_SCALE: 134 *val = 0; 135 *val2 = MMA7455_10BIT_SCALE; 136 137 return IIO_VAL_INT_PLUS_MICRO; 138 139 case IIO_CHAN_INFO_SAMP_FREQ: 140 ret = regmap_read(mma7455->regmap, MMA7455_REG_CTL1, ®); 141 if (ret) 142 return ret; 143 144 if (reg & MMA7455_CTL1_DFBW_MASK) 145 *val = 250; 146 else 147 *val = 125; 148 149 return IIO_VAL_INT; 150 } 151 152 return -EINVAL; 153 } 154 155 static int mma7455_write_raw(struct iio_dev *indio_dev, 156 struct iio_chan_spec const *chan, 157 int val, int val2, long mask) 158 { 159 struct mma7455_data *mma7455 = iio_priv(indio_dev); 160 int i; 161 162 switch (mask) { 163 case IIO_CHAN_INFO_SAMP_FREQ: 164 if (val == 250 && val2 == 0) 165 i = MMA7455_CTL1_DFBW_125HZ; 166 else if (val == 125 && val2 == 0) 167 i = MMA7455_CTL1_DFBW_62_5HZ; 168 else 169 return -EINVAL; 170 171 return regmap_update_bits(mma7455->regmap, MMA7455_REG_CTL1, 172 MMA7455_CTL1_DFBW_MASK, i); 173 174 case IIO_CHAN_INFO_SCALE: 175 /* In 10-bit mode there is only one scale available */ 176 if (val == 0 && val2 == MMA7455_10BIT_SCALE) 177 return 0; 178 break; 179 } 180 181 return -EINVAL; 182 } 183 184 static IIO_CONST_ATTR(sampling_frequency_available, "125 250"); 185 186 static struct attribute *mma7455_attributes[] = { 187 &iio_const_attr_sampling_frequency_available.dev_attr.attr, 188 NULL 189 }; 190 191 static const struct attribute_group mma7455_group = { 192 .attrs = mma7455_attributes, 193 }; 194 195 static const struct iio_info mma7455_info = { 196 .attrs = &mma7455_group, 197 .read_raw = mma7455_read_raw, 198 .write_raw = mma7455_write_raw, 199 }; 200 201 #define MMA7455_CHANNEL(axis, idx) { \ 202 .type = IIO_ACCEL, \ 203 .modified = 1, \ 204 .address = MMA7455_REG_##axis##OUTL,\ 205 .channel2 = IIO_MOD_##axis, \ 206 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 207 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 208 BIT(IIO_CHAN_INFO_SCALE), \ 209 .scan_index = idx, \ 210 .scan_type = { \ 211 .sign = 's', \ 212 .realbits = 10, \ 213 .storagebits = 16, \ 214 .endianness = IIO_LE, \ 215 }, \ 216 } 217 218 static const struct iio_chan_spec mma7455_channels[] = { 219 MMA7455_CHANNEL(X, 0), 220 MMA7455_CHANNEL(Y, 1), 221 MMA7455_CHANNEL(Z, 2), 222 IIO_CHAN_SOFT_TIMESTAMP(3), 223 }; 224 225 static const unsigned long mma7455_scan_masks[] = {0x7, 0}; 226 227 const struct regmap_config mma7455_core_regmap = { 228 .reg_bits = 8, 229 .val_bits = 8, 230 .max_register = MMA7455_REG_TW, 231 }; 232 EXPORT_SYMBOL_GPL(mma7455_core_regmap); 233 234 int mma7455_core_probe(struct device *dev, struct regmap *regmap, 235 const char *name) 236 { 237 struct mma7455_data *mma7455; 238 struct iio_dev *indio_dev; 239 unsigned int reg; 240 int ret; 241 242 ret = regmap_read(regmap, MMA7455_REG_WHOAMI, ®); 243 if (ret) { 244 dev_err(dev, "unable to read reg\n"); 245 return ret; 246 } 247 248 if (reg != MMA7455_WHOAMI_ID) { 249 dev_err(dev, "device id mismatch\n"); 250 return -ENODEV; 251 } 252 253 indio_dev = devm_iio_device_alloc(dev, sizeof(*mma7455)); 254 if (!indio_dev) 255 return -ENOMEM; 256 257 dev_set_drvdata(dev, indio_dev); 258 mma7455 = iio_priv(indio_dev); 259 mma7455->regmap = regmap; 260 261 indio_dev->info = &mma7455_info; 262 indio_dev->name = name; 263 indio_dev->dev.parent = dev; 264 indio_dev->modes = INDIO_DIRECT_MODE; 265 indio_dev->channels = mma7455_channels; 266 indio_dev->num_channels = ARRAY_SIZE(mma7455_channels); 267 indio_dev->available_scan_masks = mma7455_scan_masks; 268 269 regmap_write(mma7455->regmap, MMA7455_REG_MCTL, 270 MMA7455_MCTL_MODE_MEASURE); 271 272 ret = iio_triggered_buffer_setup(indio_dev, NULL, 273 mma7455_trigger_handler, NULL); 274 if (ret) { 275 dev_err(dev, "unable to setup triggered buffer\n"); 276 return ret; 277 } 278 279 ret = iio_device_register(indio_dev); 280 if (ret) { 281 dev_err(dev, "unable to register device\n"); 282 iio_triggered_buffer_cleanup(indio_dev); 283 return ret; 284 } 285 286 return 0; 287 } 288 EXPORT_SYMBOL_GPL(mma7455_core_probe); 289 290 int mma7455_core_remove(struct device *dev) 291 { 292 struct iio_dev *indio_dev = dev_get_drvdata(dev); 293 struct mma7455_data *mma7455 = iio_priv(indio_dev); 294 295 iio_device_unregister(indio_dev); 296 iio_triggered_buffer_cleanup(indio_dev); 297 298 regmap_write(mma7455->regmap, MMA7455_REG_MCTL, 299 MMA7455_MCTL_MODE_STANDBY); 300 301 return 0; 302 } 303 EXPORT_SYMBOL_GPL(mma7455_core_remove); 304 305 MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); 306 MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver"); 307 MODULE_LICENSE("GPL v2"); 308