cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mma7455_core.c (7471B)


      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	 * Used to reorganize data.  Will ensure correct alignment of
     57	 * the timestamp if present
     58	 */
     59	struct {
     60		__le16 channels[3];
     61		s64 ts __aligned(8);
     62	} scan;
     63};
     64
     65static int mma7455_drdy(struct mma7455_data *mma7455)
     66{
     67	struct device *dev = regmap_get_device(mma7455->regmap);
     68	unsigned int reg;
     69	int tries = 3;
     70	int ret;
     71
     72	while (tries-- > 0) {
     73		ret = regmap_read(mma7455->regmap, MMA7455_REG_STATUS, &reg);
     74		if (ret)
     75			return ret;
     76
     77		if (reg & MMA7455_STATUS_DRDY)
     78			return 0;
     79
     80		msleep(20);
     81	}
     82
     83	dev_warn(dev, "data not ready\n");
     84
     85	return -EIO;
     86}
     87
     88static irqreturn_t mma7455_trigger_handler(int irq, void *p)
     89{
     90	struct iio_poll_func *pf = p;
     91	struct iio_dev *indio_dev = pf->indio_dev;
     92	struct mma7455_data *mma7455 = iio_priv(indio_dev);
     93	int ret;
     94
     95	ret = mma7455_drdy(mma7455);
     96	if (ret)
     97		goto done;
     98
     99	ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL,
    100			       mma7455->scan.channels,
    101			       sizeof(mma7455->scan.channels));
    102	if (ret)
    103		goto done;
    104
    105	iio_push_to_buffers_with_timestamp(indio_dev, &mma7455->scan,
    106					   iio_get_time_ns(indio_dev));
    107
    108done:
    109	iio_trigger_notify_done(indio_dev->trig);
    110
    111	return IRQ_HANDLED;
    112}
    113
    114static int mma7455_read_raw(struct iio_dev *indio_dev,
    115			    struct iio_chan_spec const *chan,
    116			    int *val, int *val2, long mask)
    117{
    118	struct mma7455_data *mma7455 = iio_priv(indio_dev);
    119	unsigned int reg;
    120	__le16 data;
    121	int ret;
    122
    123	switch (mask) {
    124	case IIO_CHAN_INFO_RAW:
    125		if (iio_buffer_enabled(indio_dev))
    126			return -EBUSY;
    127
    128		ret = mma7455_drdy(mma7455);
    129		if (ret)
    130			return ret;
    131
    132		ret = regmap_bulk_read(mma7455->regmap, chan->address, &data,
    133				       sizeof(data));
    134		if (ret)
    135			return ret;
    136
    137		*val = sign_extend32(le16_to_cpu(data),
    138				     chan->scan_type.realbits - 1);
    139
    140		return IIO_VAL_INT;
    141
    142	case IIO_CHAN_INFO_SCALE:
    143		*val = 0;
    144		*val2 = MMA7455_10BIT_SCALE;
    145
    146		return IIO_VAL_INT_PLUS_MICRO;
    147
    148	case IIO_CHAN_INFO_SAMP_FREQ:
    149		ret = regmap_read(mma7455->regmap, MMA7455_REG_CTL1, &reg);
    150		if (ret)
    151			return ret;
    152
    153		if (reg & MMA7455_CTL1_DFBW_MASK)
    154			*val = 250;
    155		else
    156			*val = 125;
    157
    158		return IIO_VAL_INT;
    159	}
    160
    161	return -EINVAL;
    162}
    163
    164static int mma7455_write_raw(struct iio_dev *indio_dev,
    165			     struct iio_chan_spec const *chan,
    166			     int val, int val2, long mask)
    167{
    168	struct mma7455_data *mma7455 = iio_priv(indio_dev);
    169	int i;
    170
    171	switch (mask) {
    172	case IIO_CHAN_INFO_SAMP_FREQ:
    173		if (val == 250 && val2 == 0)
    174			i = MMA7455_CTL1_DFBW_125HZ;
    175		else if (val == 125 && val2 == 0)
    176			i = MMA7455_CTL1_DFBW_62_5HZ;
    177		else
    178			return -EINVAL;
    179
    180		return regmap_update_bits(mma7455->regmap, MMA7455_REG_CTL1,
    181					  MMA7455_CTL1_DFBW_MASK, i);
    182
    183	case IIO_CHAN_INFO_SCALE:
    184		/* In 10-bit mode there is only one scale available */
    185		if (val == 0 && val2 == MMA7455_10BIT_SCALE)
    186			return 0;
    187		break;
    188	}
    189
    190	return -EINVAL;
    191}
    192
    193static IIO_CONST_ATTR(sampling_frequency_available, "125 250");
    194
    195static struct attribute *mma7455_attributes[] = {
    196	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
    197	NULL
    198};
    199
    200static const struct attribute_group mma7455_group = {
    201	.attrs = mma7455_attributes,
    202};
    203
    204static const struct iio_info mma7455_info = {
    205	.attrs = &mma7455_group,
    206	.read_raw = mma7455_read_raw,
    207	.write_raw = mma7455_write_raw,
    208};
    209
    210#define MMA7455_CHANNEL(axis, idx) { \
    211	.type = IIO_ACCEL, \
    212	.modified = 1, \
    213	.address = MMA7455_REG_##axis##OUTL,\
    214	.channel2 = IIO_MOD_##axis, \
    215	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
    216	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
    217				    BIT(IIO_CHAN_INFO_SCALE), \
    218	.scan_index = idx, \
    219	.scan_type = { \
    220		.sign = 's', \
    221		.realbits = 10, \
    222		.storagebits = 16, \
    223		.endianness = IIO_LE, \
    224	}, \
    225}
    226
    227static const struct iio_chan_spec mma7455_channels[] = {
    228	MMA7455_CHANNEL(X, 0),
    229	MMA7455_CHANNEL(Y, 1),
    230	MMA7455_CHANNEL(Z, 2),
    231	IIO_CHAN_SOFT_TIMESTAMP(3),
    232};
    233
    234static const unsigned long mma7455_scan_masks[] = {0x7, 0};
    235
    236const struct regmap_config mma7455_core_regmap = {
    237	.reg_bits = 8,
    238	.val_bits = 8,
    239	.max_register = MMA7455_REG_TW,
    240};
    241EXPORT_SYMBOL_NS_GPL(mma7455_core_regmap, IIO_MMA7455);
    242
    243int mma7455_core_probe(struct device *dev, struct regmap *regmap,
    244		       const char *name)
    245{
    246	struct mma7455_data *mma7455;
    247	struct iio_dev *indio_dev;
    248	unsigned int reg;
    249	int ret;
    250
    251	ret = regmap_read(regmap, MMA7455_REG_WHOAMI, &reg);
    252	if (ret) {
    253		dev_err(dev, "unable to read reg\n");
    254		return ret;
    255	}
    256
    257	if (reg != MMA7455_WHOAMI_ID) {
    258		dev_err(dev, "device id mismatch\n");
    259		return -ENODEV;
    260	}
    261
    262	indio_dev = devm_iio_device_alloc(dev, sizeof(*mma7455));
    263	if (!indio_dev)
    264		return -ENOMEM;
    265
    266	dev_set_drvdata(dev, indio_dev);
    267	mma7455 = iio_priv(indio_dev);
    268	mma7455->regmap = regmap;
    269
    270	indio_dev->info = &mma7455_info;
    271	indio_dev->name = name;
    272	indio_dev->modes = INDIO_DIRECT_MODE;
    273	indio_dev->channels = mma7455_channels;
    274	indio_dev->num_channels = ARRAY_SIZE(mma7455_channels);
    275	indio_dev->available_scan_masks = mma7455_scan_masks;
    276
    277	regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
    278		     MMA7455_MCTL_MODE_MEASURE);
    279
    280	ret = iio_triggered_buffer_setup(indio_dev, NULL,
    281					 mma7455_trigger_handler, NULL);
    282	if (ret) {
    283		dev_err(dev, "unable to setup triggered buffer\n");
    284		return ret;
    285	}
    286
    287	ret = iio_device_register(indio_dev);
    288	if (ret) {
    289		dev_err(dev, "unable to register device\n");
    290		iio_triggered_buffer_cleanup(indio_dev);
    291		return ret;
    292	}
    293
    294	return 0;
    295}
    296EXPORT_SYMBOL_NS_GPL(mma7455_core_probe, IIO_MMA7455);
    297
    298void mma7455_core_remove(struct device *dev)
    299{
    300	struct iio_dev *indio_dev = dev_get_drvdata(dev);
    301	struct mma7455_data *mma7455 = iio_priv(indio_dev);
    302
    303	iio_device_unregister(indio_dev);
    304	iio_triggered_buffer_cleanup(indio_dev);
    305
    306	regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
    307		     MMA7455_MCTL_MODE_STANDBY);
    308}
    309EXPORT_SYMBOL_NS_GPL(mma7455_core_remove, IIO_MMA7455);
    310
    311MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
    312MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver");
    313MODULE_LICENSE("GPL v2");