Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.4-rc5 307 lines 7.3 kB view raw
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 53struct mma7455_data { 54 struct regmap *regmap; 55}; 56 57static 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, &reg); 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 80static 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 100done: 101 iio_trigger_notify_done(indio_dev->trig); 102 103 return IRQ_HANDLED; 104} 105 106static 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, &reg); 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 155static 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 184static IIO_CONST_ATTR(sampling_frequency_available, "125 250"); 185 186static struct attribute *mma7455_attributes[] = { 187 &iio_const_attr_sampling_frequency_available.dev_attr.attr, 188 NULL 189}; 190 191static const struct attribute_group mma7455_group = { 192 .attrs = mma7455_attributes, 193}; 194 195static 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 218static 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 225static const unsigned long mma7455_scan_masks[] = {0x7, 0}; 226 227const struct regmap_config mma7455_core_regmap = { 228 .reg_bits = 8, 229 .val_bits = 8, 230 .max_register = MMA7455_REG_TW, 231}; 232EXPORT_SYMBOL_GPL(mma7455_core_regmap); 233 234int 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, &reg); 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} 288EXPORT_SYMBOL_GPL(mma7455_core_probe); 289 290int 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} 303EXPORT_SYMBOL_GPL(mma7455_core_remove); 304 305MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); 306MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver"); 307MODULE_LICENSE("GPL v2");