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

adxl345_core.c (7428B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ADXL345 3-Axis Digital Accelerometer IIO core driver
      4 *
      5 * Copyright (c) 2017 Eva Rachel Retuya <eraretuya@gmail.com>
      6 *
      7 * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/property.h>
     12#include <linux/regmap.h>
     13
     14#include <linux/iio/iio.h>
     15#include <linux/iio/sysfs.h>
     16
     17#include "adxl345.h"
     18
     19#define ADXL345_REG_DEVID		0x00
     20#define ADXL345_REG_OFSX		0x1e
     21#define ADXL345_REG_OFSY		0x1f
     22#define ADXL345_REG_OFSZ		0x20
     23#define ADXL345_REG_OFS_AXIS(index)	(ADXL345_REG_OFSX + (index))
     24#define ADXL345_REG_BW_RATE		0x2C
     25#define ADXL345_REG_POWER_CTL		0x2D
     26#define ADXL345_REG_DATA_FORMAT		0x31
     27#define ADXL345_REG_DATAX0		0x32
     28#define ADXL345_REG_DATAY0		0x34
     29#define ADXL345_REG_DATAZ0		0x36
     30#define ADXL345_REG_DATA_AXIS(index)	\
     31	(ADXL345_REG_DATAX0 + (index) * sizeof(__le16))
     32
     33#define ADXL345_BW_RATE			GENMASK(3, 0)
     34#define ADXL345_BASE_RATE_NANO_HZ	97656250LL
     35#define NHZ_PER_HZ			1000000000LL
     36
     37#define ADXL345_POWER_CTL_MEASURE	BIT(3)
     38#define ADXL345_POWER_CTL_STANDBY	0x00
     39
     40#define ADXL345_DATA_FORMAT_FULL_RES	BIT(3) /* Up to 13-bits resolution */
     41#define ADXL345_DATA_FORMAT_2G		0
     42#define ADXL345_DATA_FORMAT_4G		1
     43#define ADXL345_DATA_FORMAT_8G		2
     44#define ADXL345_DATA_FORMAT_16G		3
     45
     46#define ADXL345_DEVID			0xE5
     47
     48/*
     49 * In full-resolution mode, scale factor is maintained at ~4 mg/LSB
     50 * in all g ranges.
     51 *
     52 * At +/- 16g with 13-bit resolution, scale is computed as:
     53 * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383
     54 */
     55static const int adxl345_uscale = 38300;
     56
     57/*
     58 * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's
     59 * ~480mm/s**2 per LSB.
     60 */
     61static const int adxl375_uscale = 480000;
     62
     63struct adxl345_data {
     64	struct regmap *regmap;
     65	u8 data_range;
     66	enum adxl345_device_type type;
     67};
     68
     69#define ADXL345_CHANNEL(index, axis) {					\
     70	.type = IIO_ACCEL,						\
     71	.modified = 1,							\
     72	.channel2 = IIO_MOD_##axis,					\
     73	.address = index,						\
     74	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
     75		BIT(IIO_CHAN_INFO_CALIBBIAS),				\
     76	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |		\
     77		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
     78}
     79
     80static const struct iio_chan_spec adxl345_channels[] = {
     81	ADXL345_CHANNEL(0, X),
     82	ADXL345_CHANNEL(1, Y),
     83	ADXL345_CHANNEL(2, Z),
     84};
     85
     86static int adxl345_read_raw(struct iio_dev *indio_dev,
     87			    struct iio_chan_spec const *chan,
     88			    int *val, int *val2, long mask)
     89{
     90	struct adxl345_data *data = iio_priv(indio_dev);
     91	__le16 accel;
     92	long long samp_freq_nhz;
     93	unsigned int regval;
     94	int ret;
     95
     96	switch (mask) {
     97	case IIO_CHAN_INFO_RAW:
     98		/*
     99		 * Data is stored in adjacent registers:
    100		 * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte
    101		 * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte
    102		 */
    103		ret = regmap_bulk_read(data->regmap,
    104				       ADXL345_REG_DATA_AXIS(chan->address),
    105				       &accel, sizeof(accel));
    106		if (ret < 0)
    107			return ret;
    108
    109		*val = sign_extend32(le16_to_cpu(accel), 12);
    110		return IIO_VAL_INT;
    111	case IIO_CHAN_INFO_SCALE:
    112		*val = 0;
    113		switch (data->type) {
    114		case ADXL345:
    115			*val2 = adxl345_uscale;
    116			break;
    117		case ADXL375:
    118			*val2 = adxl375_uscale;
    119			break;
    120		}
    121
    122		return IIO_VAL_INT_PLUS_MICRO;
    123	case IIO_CHAN_INFO_CALIBBIAS:
    124		ret = regmap_read(data->regmap,
    125				  ADXL345_REG_OFS_AXIS(chan->address), &regval);
    126		if (ret < 0)
    127			return ret;
    128		/*
    129		 * 8-bit resolution at +/- 2g, that is 4x accel data scale
    130		 * factor
    131		 */
    132		*val = sign_extend32(regval, 7) * 4;
    133
    134		return IIO_VAL_INT;
    135	case IIO_CHAN_INFO_SAMP_FREQ:
    136		ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, &regval);
    137		if (ret < 0)
    138			return ret;
    139
    140		samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ <<
    141				(regval & ADXL345_BW_RATE);
    142		*val = div_s64_rem(samp_freq_nhz, NHZ_PER_HZ, val2);
    143
    144		return IIO_VAL_INT_PLUS_NANO;
    145	}
    146
    147	return -EINVAL;
    148}
    149
    150static int adxl345_write_raw(struct iio_dev *indio_dev,
    151			     struct iio_chan_spec const *chan,
    152			     int val, int val2, long mask)
    153{
    154	struct adxl345_data *data = iio_priv(indio_dev);
    155	s64 n;
    156
    157	switch (mask) {
    158	case IIO_CHAN_INFO_CALIBBIAS:
    159		/*
    160		 * 8-bit resolution at +/- 2g, that is 4x accel data scale
    161		 * factor
    162		 */
    163		return regmap_write(data->regmap,
    164				    ADXL345_REG_OFS_AXIS(chan->address),
    165				    val / 4);
    166	case IIO_CHAN_INFO_SAMP_FREQ:
    167		n = div_s64(val * NHZ_PER_HZ + val2, ADXL345_BASE_RATE_NANO_HZ);
    168
    169		return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE,
    170					  ADXL345_BW_RATE,
    171					  clamp_val(ilog2(n), 0,
    172						    ADXL345_BW_RATE));
    173	}
    174
    175	return -EINVAL;
    176}
    177
    178static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
    179				     struct iio_chan_spec const *chan,
    180				     long mask)
    181{
    182	switch (mask) {
    183	case IIO_CHAN_INFO_CALIBBIAS:
    184		return IIO_VAL_INT;
    185	case IIO_CHAN_INFO_SAMP_FREQ:
    186		return IIO_VAL_INT_PLUS_NANO;
    187	default:
    188		return -EINVAL;
    189	}
    190}
    191
    192static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
    193"0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200"
    194);
    195
    196static struct attribute *adxl345_attrs[] = {
    197	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
    198	NULL
    199};
    200
    201static const struct attribute_group adxl345_attrs_group = {
    202	.attrs = adxl345_attrs,
    203};
    204
    205static const struct iio_info adxl345_info = {
    206	.attrs		= &adxl345_attrs_group,
    207	.read_raw	= adxl345_read_raw,
    208	.write_raw	= adxl345_write_raw,
    209	.write_raw_get_fmt	= adxl345_write_raw_get_fmt,
    210};
    211
    212static int adxl345_powerup(void *regmap)
    213{
    214	return regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_MEASURE);
    215}
    216
    217static void adxl345_powerdown(void *regmap)
    218{
    219	regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY);
    220}
    221
    222int adxl345_core_probe(struct device *dev, struct regmap *regmap)
    223{
    224	enum adxl345_device_type type;
    225	struct adxl345_data *data;
    226	struct iio_dev *indio_dev;
    227	const char *name;
    228	u32 regval;
    229	int ret;
    230
    231	type = (uintptr_t)device_get_match_data(dev);
    232	switch (type) {
    233	case ADXL345:
    234		name = "adxl345";
    235		break;
    236	case ADXL375:
    237		name = "adxl375";
    238		break;
    239	default:
    240		return -EINVAL;
    241	}
    242
    243	ret = regmap_read(regmap, ADXL345_REG_DEVID, &regval);
    244	if (ret < 0)
    245		return dev_err_probe(dev, ret, "Error reading device ID\n");
    246
    247	if (regval != ADXL345_DEVID)
    248		return dev_err_probe(dev, -ENODEV, "Invalid device ID: %x, expected %x\n",
    249				     regval, ADXL345_DEVID);
    250
    251	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
    252	if (!indio_dev)
    253		return -ENOMEM;
    254
    255	data = iio_priv(indio_dev);
    256	data->regmap = regmap;
    257	data->type = type;
    258	/* Enable full-resolution mode */
    259	data->data_range = ADXL345_DATA_FORMAT_FULL_RES;
    260
    261	ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
    262			   data->data_range);
    263	if (ret < 0)
    264		return dev_err_probe(dev, ret, "Failed to set data range\n");
    265
    266	indio_dev->name = name;
    267	indio_dev->info = &adxl345_info;
    268	indio_dev->modes = INDIO_DIRECT_MODE;
    269	indio_dev->channels = adxl345_channels;
    270	indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
    271
    272	/* Enable measurement mode */
    273	ret = adxl345_powerup(data->regmap);
    274	if (ret < 0)
    275		return dev_err_probe(dev, ret, "Failed to enable measurement mode\n");
    276
    277	ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap);
    278	if (ret < 0)
    279		return ret;
    280
    281	return devm_iio_device_register(dev, indio_dev);
    282}
    283EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, IIO_ADXL345);
    284
    285MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>");
    286MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver");
    287MODULE_LICENSE("GPL v2");