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

adxl313_core.c (8986B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ADXL313 3-Axis Digital Accelerometer
      4 *
      5 * Copyright (c) 2021 Lucas Stankus <lucas.p.stankus@gmail.com>
      6 *
      7 * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf
      8 */
      9
     10#include <linux/bitfield.h>
     11#include <linux/iio/iio.h>
     12#include <linux/module.h>
     13#include <linux/regmap.h>
     14
     15#include "adxl313.h"
     16
     17static const struct regmap_range adxl313_readable_reg_range[] = {
     18	regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_XID),
     19	regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET),
     20	regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
     21	regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),
     22	regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_FIFO_STATUS),
     23};
     24
     25const struct regmap_access_table adxl313_readable_regs_table = {
     26	.yes_ranges = adxl313_readable_reg_range,
     27	.n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range),
     28};
     29EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, IIO_ADXL313);
     30
     31static const struct regmap_range adxl313_writable_reg_range[] = {
     32	regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET),
     33	regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
     34	regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),
     35	regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_INT_MAP),
     36	regmap_reg_range(ADXL313_REG_DATA_FORMAT, ADXL313_REG_DATA_FORMAT),
     37	regmap_reg_range(ADXL313_REG_FIFO_CTL, ADXL313_REG_FIFO_CTL),
     38};
     39
     40const struct regmap_access_table adxl313_writable_regs_table = {
     41	.yes_ranges = adxl313_writable_reg_range,
     42	.n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range),
     43};
     44EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, IIO_ADXL313);
     45
     46struct adxl313_data {
     47	struct regmap	*regmap;
     48	struct mutex	lock; /* lock to protect transf_buf */
     49	__le16		transf_buf ____cacheline_aligned;
     50};
     51
     52static const int adxl313_odr_freqs[][2] = {
     53	[0] = { 6, 250000 },
     54	[1] = { 12, 500000 },
     55	[2] = { 25, 0 },
     56	[3] = { 50, 0 },
     57	[4] = { 100, 0 },
     58	[5] = { 200, 0 },
     59	[6] = { 400, 0 },
     60	[7] = { 800, 0 },
     61	[8] = { 1600, 0 },
     62	[9] = { 3200, 0 },
     63};
     64
     65#define ADXL313_ACCEL_CHANNEL(index, axis) {				\
     66	.type = IIO_ACCEL,						\
     67	.address = index,						\
     68	.modified = 1,							\
     69	.channel2 = IIO_MOD_##axis,					\
     70	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
     71			      BIT(IIO_CHAN_INFO_CALIBBIAS),		\
     72	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |		\
     73				    BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
     74	.info_mask_shared_by_type_available =				\
     75		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
     76	.scan_type = {							\
     77		.realbits = 13,						\
     78	},								\
     79}
     80
     81static const struct iio_chan_spec adxl313_channels[] = {
     82	ADXL313_ACCEL_CHANNEL(0, X),
     83	ADXL313_ACCEL_CHANNEL(1, Y),
     84	ADXL313_ACCEL_CHANNEL(2, Z),
     85};
     86
     87static int adxl313_set_odr(struct adxl313_data *data,
     88			   unsigned int freq1, unsigned int freq2)
     89{
     90	unsigned int i;
     91
     92	for (i = 0; i < ARRAY_SIZE(adxl313_odr_freqs); i++) {
     93		if (adxl313_odr_freqs[i][0] == freq1 &&
     94		    adxl313_odr_freqs[i][1] == freq2)
     95			break;
     96	}
     97
     98	if (i == ARRAY_SIZE(adxl313_odr_freqs))
     99		return -EINVAL;
    100
    101	return regmap_update_bits(data->regmap, ADXL313_REG_BW_RATE,
    102				  ADXL313_RATE_MSK,
    103				  FIELD_PREP(ADXL313_RATE_MSK, ADXL313_RATE_BASE + i));
    104}
    105
    106static int adxl313_read_axis(struct adxl313_data *data,
    107			     struct iio_chan_spec const *chan)
    108{
    109	int ret;
    110
    111	mutex_lock(&data->lock);
    112
    113	ret = regmap_bulk_read(data->regmap,
    114			       ADXL313_REG_DATA_AXIS(chan->address),
    115			       &data->transf_buf, sizeof(data->transf_buf));
    116	if (ret)
    117		goto unlock_ret;
    118
    119	ret = le16_to_cpu(data->transf_buf);
    120
    121unlock_ret:
    122	mutex_unlock(&data->lock);
    123	return ret;
    124}
    125
    126static int adxl313_read_freq_avail(struct iio_dev *indio_dev,
    127				   struct iio_chan_spec const *chan,
    128				   const int **vals, int *type, int *length,
    129				   long mask)
    130{
    131	switch (mask) {
    132	case IIO_CHAN_INFO_SAMP_FREQ:
    133		*vals = (const int *)adxl313_odr_freqs;
    134		*length = ARRAY_SIZE(adxl313_odr_freqs) * 2;
    135		*type = IIO_VAL_INT_PLUS_MICRO;
    136		return IIO_AVAIL_LIST;
    137	default:
    138		return -EINVAL;
    139	}
    140}
    141
    142static int adxl313_read_raw(struct iio_dev *indio_dev,
    143			    struct iio_chan_spec const *chan,
    144			    int *val, int *val2, long mask)
    145{
    146	struct adxl313_data *data = iio_priv(indio_dev);
    147	unsigned int regval;
    148	int ret;
    149
    150	switch (mask) {
    151	case IIO_CHAN_INFO_RAW:
    152		ret = adxl313_read_axis(data, chan);
    153		if (ret < 0)
    154			return ret;
    155
    156		*val = sign_extend32(ret, chan->scan_type.realbits - 1);
    157		return IIO_VAL_INT;
    158	case IIO_CHAN_INFO_SCALE:
    159		/*
    160		 * Scale for any g range is given in datasheet as
    161		 * 1024 LSB/g = 0.0009765625 * 9.80665 = 0.009576806640625 m/s^2
    162		 */
    163		*val = 0;
    164		*val2 = 9576806;
    165		return IIO_VAL_INT_PLUS_NANO;
    166	case IIO_CHAN_INFO_CALIBBIAS:
    167		ret = regmap_read(data->regmap,
    168				  ADXL313_REG_OFS_AXIS(chan->address), &regval);
    169		if (ret)
    170			return ret;
    171
    172		/*
    173		 * 8-bit resolution at +/- 0.5g, that is 4x accel data scale
    174		 * factor at full resolution
    175		 */
    176		*val = sign_extend32(regval, 7) * 4;
    177		return IIO_VAL_INT;
    178	case IIO_CHAN_INFO_SAMP_FREQ:
    179		ret = regmap_read(data->regmap, ADXL313_REG_BW_RATE, &regval);
    180		if (ret)
    181			return ret;
    182
    183		ret = FIELD_GET(ADXL313_RATE_MSK, regval) - ADXL313_RATE_BASE;
    184		*val = adxl313_odr_freqs[ret][0];
    185		*val2 = adxl313_odr_freqs[ret][1];
    186		return IIO_VAL_INT_PLUS_MICRO;
    187	default:
    188		return -EINVAL;
    189	}
    190}
    191
    192static int adxl313_write_raw(struct iio_dev *indio_dev,
    193			     struct iio_chan_spec const *chan,
    194			     int val, int val2, long mask)
    195{
    196	struct adxl313_data *data = iio_priv(indio_dev);
    197
    198	switch (mask) {
    199	case IIO_CHAN_INFO_CALIBBIAS:
    200		/*
    201		 * 8-bit resolution at +/- 0.5g, that is 4x accel data scale
    202		 * factor at full resolution
    203		 */
    204		if (clamp_val(val, -128 * 4, 127 * 4) != val)
    205			return -EINVAL;
    206
    207		return regmap_write(data->regmap,
    208				    ADXL313_REG_OFS_AXIS(chan->address),
    209				    val / 4);
    210	case IIO_CHAN_INFO_SAMP_FREQ:
    211		return adxl313_set_odr(data, val, val2);
    212	default:
    213		return -EINVAL;
    214	}
    215}
    216
    217static const struct iio_info adxl313_info = {
    218	.read_raw	= adxl313_read_raw,
    219	.write_raw	= adxl313_write_raw,
    220	.read_avail	= adxl313_read_freq_avail,
    221};
    222
    223static int adxl313_setup(struct device *dev, struct adxl313_data *data,
    224			 int (*setup)(struct device *, struct regmap *))
    225{
    226	unsigned int regval;
    227	int ret;
    228
    229	/* Ensures the device is in a consistent state after start up */
    230	ret = regmap_write(data->regmap, ADXL313_REG_SOFT_RESET,
    231			   ADXL313_SOFT_RESET);
    232	if (ret)
    233		return ret;
    234
    235	if (setup) {
    236		ret = setup(dev, data->regmap);
    237		if (ret)
    238			return ret;
    239	}
    240
    241	ret = regmap_read(data->regmap, ADXL313_REG_DEVID0, &regval);
    242	if (ret)
    243		return ret;
    244
    245	if (regval != ADXL313_DEVID0) {
    246		dev_err(dev, "Invalid manufacturer ID: 0x%02x\n", regval);
    247		return -ENODEV;
    248	}
    249
    250	ret = regmap_read(data->regmap, ADXL313_REG_DEVID1, &regval);
    251	if (ret)
    252		return ret;
    253
    254	if (regval != ADXL313_DEVID1) {
    255		dev_err(dev, "Invalid mems ID: 0x%02x\n", regval);
    256		return -ENODEV;
    257	}
    258
    259	ret = regmap_read(data->regmap, ADXL313_REG_PARTID, &regval);
    260	if (ret)
    261		return ret;
    262
    263	if (regval != ADXL313_PARTID) {
    264		dev_err(dev, "Invalid device ID: 0x%02x\n", regval);
    265		return -ENODEV;
    266	}
    267
    268	/* Sets the range to +/- 4g */
    269	ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT,
    270				 ADXL313_RANGE_MSK,
    271				 FIELD_PREP(ADXL313_RANGE_MSK, ADXL313_RANGE_4G));
    272	if (ret)
    273		return ret;
    274
    275	/* Enables full resolution */
    276	ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT,
    277				 ADXL313_FULL_RES, ADXL313_FULL_RES);
    278	if (ret)
    279		return ret;
    280
    281	/* Enables measurement mode */
    282	return regmap_update_bits(data->regmap, ADXL313_REG_POWER_CTL,
    283				  ADXL313_POWER_CTL_MSK,
    284				  ADXL313_MEASUREMENT_MODE);
    285}
    286
    287/**
    288 * adxl313_core_probe() - probe and setup for adxl313 accelerometer
    289 * @dev:	Driver model representation of the device
    290 * @regmap:	Register map of the device
    291 * @name:	Device name buffer reference
    292 * @setup:	Setup routine to be executed right before the standard device
    293 *		setup, can also be set to NULL if not required
    294 *
    295 * Return: 0 on success, negative errno on error cases
    296 */
    297int adxl313_core_probe(struct device *dev,
    298		       struct regmap *regmap,
    299		       const char *name,
    300		       int (*setup)(struct device *, struct regmap *))
    301{
    302	struct adxl313_data *data;
    303	struct iio_dev *indio_dev;
    304	int ret;
    305
    306	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
    307	if (!indio_dev)
    308		return -ENOMEM;
    309
    310	data = iio_priv(indio_dev);
    311	data->regmap = regmap;
    312	mutex_init(&data->lock);
    313
    314	indio_dev->name = name;
    315	indio_dev->info = &adxl313_info;
    316	indio_dev->modes = INDIO_DIRECT_MODE;
    317	indio_dev->channels = adxl313_channels;
    318	indio_dev->num_channels = ARRAY_SIZE(adxl313_channels);
    319
    320	ret = adxl313_setup(dev, data, setup);
    321	if (ret) {
    322		dev_err(dev, "ADXL313 setup failed\n");
    323		return ret;
    324	}
    325
    326	return devm_iio_device_register(dev, indio_dev);
    327}
    328EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, IIO_ADXL313);
    329
    330MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>");
    331MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver");
    332MODULE_LICENSE("GPL v2");