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

dmard06.c (5690B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * IIO driver for Domintech DMARD06 accelerometer
      4 *
      5 * Copyright (C) 2016 Aleksei Mamlin <mamlinav@gmail.com>
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/mod_devicetable.h>
     10#include <linux/i2c.h>
     11#include <linux/iio/iio.h>
     12
     13#define DMARD06_DRV_NAME		"dmard06"
     14
     15/* Device data registers */
     16#define DMARD06_CHIP_ID_REG		0x0f
     17#define DMARD06_TOUT_REG		0x40
     18#define DMARD06_XOUT_REG		0x41
     19#define DMARD06_YOUT_REG		0x42
     20#define DMARD06_ZOUT_REG		0x43
     21#define DMARD06_CTRL1_REG		0x44
     22
     23/* Device ID value */
     24#define DMARD05_CHIP_ID			0x05
     25#define DMARD06_CHIP_ID			0x06
     26#define DMARD07_CHIP_ID			0x07
     27
     28/* Device values */
     29#define DMARD05_AXIS_SCALE_VAL		15625
     30#define DMARD06_AXIS_SCALE_VAL		31250
     31#define DMARD06_TEMP_CENTER_VAL		25
     32#define DMARD06_SIGN_BIT		7
     33
     34/* Device power modes */
     35#define DMARD06_MODE_NORMAL		0x27
     36#define DMARD06_MODE_POWERDOWN		0x00
     37
     38/* Device channels */
     39#define DMARD06_ACCEL_CHANNEL(_axis, _reg) {			\
     40	.type = IIO_ACCEL,					\
     41	.address = _reg,					\
     42	.channel2 = IIO_MOD_##_axis,				\
     43	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
     44	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
     45	.modified = 1,						\
     46}
     47
     48#define DMARD06_TEMP_CHANNEL(_reg) {				\
     49	.type = IIO_TEMP,					\
     50	.address = _reg,					\
     51	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
     52			      BIT(IIO_CHAN_INFO_OFFSET),	\
     53}
     54
     55struct dmard06_data {
     56	struct i2c_client *client;
     57	u8 chip_id;
     58};
     59
     60static const struct iio_chan_spec dmard06_channels[] = {
     61	DMARD06_ACCEL_CHANNEL(X, DMARD06_XOUT_REG),
     62	DMARD06_ACCEL_CHANNEL(Y, DMARD06_YOUT_REG),
     63	DMARD06_ACCEL_CHANNEL(Z, DMARD06_ZOUT_REG),
     64	DMARD06_TEMP_CHANNEL(DMARD06_TOUT_REG),
     65};
     66
     67static int dmard06_read_raw(struct iio_dev *indio_dev,
     68			    struct iio_chan_spec const *chan,
     69			    int *val, int *val2, long mask)
     70{
     71	struct dmard06_data *dmard06 = iio_priv(indio_dev);
     72	int ret;
     73
     74	switch (mask) {
     75	case IIO_CHAN_INFO_RAW:
     76		ret = i2c_smbus_read_byte_data(dmard06->client,
     77					       chan->address);
     78		if (ret < 0) {
     79			dev_err(&dmard06->client->dev,
     80				"Error reading data: %d\n", ret);
     81			return ret;
     82		}
     83
     84		*val = sign_extend32(ret, DMARD06_SIGN_BIT);
     85
     86		if (dmard06->chip_id == DMARD06_CHIP_ID)
     87			*val = *val >> 1;
     88
     89		switch (chan->type) {
     90		case IIO_ACCEL:
     91			return IIO_VAL_INT;
     92		case IIO_TEMP:
     93			if (dmard06->chip_id != DMARD06_CHIP_ID)
     94				*val = *val / 2;
     95			return IIO_VAL_INT;
     96		default:
     97			return -EINVAL;
     98		}
     99	case IIO_CHAN_INFO_OFFSET:
    100		switch (chan->type) {
    101		case IIO_TEMP:
    102			*val = DMARD06_TEMP_CENTER_VAL;
    103			return IIO_VAL_INT;
    104		default:
    105			return -EINVAL;
    106		}
    107	case IIO_CHAN_INFO_SCALE:
    108		switch (chan->type) {
    109		case IIO_ACCEL:
    110			*val = 0;
    111			if (dmard06->chip_id == DMARD06_CHIP_ID)
    112				*val2 = DMARD06_AXIS_SCALE_VAL;
    113			else
    114				*val2 = DMARD05_AXIS_SCALE_VAL;
    115			return IIO_VAL_INT_PLUS_MICRO;
    116		default:
    117			return -EINVAL;
    118		}
    119	default:
    120		return -EINVAL;
    121	}
    122}
    123
    124static const struct iio_info dmard06_info = {
    125	.read_raw	= dmard06_read_raw,
    126};
    127
    128static int dmard06_probe(struct i2c_client *client,
    129			const struct i2c_device_id *id)
    130{
    131	int ret;
    132	struct iio_dev *indio_dev;
    133	struct dmard06_data *dmard06;
    134
    135	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
    136		dev_err(&client->dev, "I2C check functionality failed\n");
    137		return -ENXIO;
    138	}
    139
    140	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dmard06));
    141	if (!indio_dev) {
    142		dev_err(&client->dev, "Failed to allocate iio device\n");
    143		return -ENOMEM;
    144	}
    145
    146	dmard06 = iio_priv(indio_dev);
    147	dmard06->client = client;
    148
    149	ret = i2c_smbus_read_byte_data(dmard06->client, DMARD06_CHIP_ID_REG);
    150	if (ret < 0) {
    151		dev_err(&client->dev, "Error reading chip id: %d\n", ret);
    152		return ret;
    153	}
    154
    155	if (ret != DMARD05_CHIP_ID && ret != DMARD06_CHIP_ID &&
    156	    ret != DMARD07_CHIP_ID) {
    157		dev_err(&client->dev, "Invalid chip id: %02d\n", ret);
    158		return -ENODEV;
    159	}
    160
    161	dmard06->chip_id = ret;
    162
    163	i2c_set_clientdata(client, indio_dev);
    164	indio_dev->name = DMARD06_DRV_NAME;
    165	indio_dev->modes = INDIO_DIRECT_MODE;
    166	indio_dev->channels = dmard06_channels;
    167	indio_dev->num_channels = ARRAY_SIZE(dmard06_channels);
    168	indio_dev->info = &dmard06_info;
    169
    170	return devm_iio_device_register(&client->dev, indio_dev);
    171}
    172
    173static int dmard06_suspend(struct device *dev)
    174{
    175	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
    176	struct dmard06_data *dmard06 = iio_priv(indio_dev);
    177	int ret;
    178
    179	ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
    180					DMARD06_MODE_POWERDOWN);
    181	if (ret < 0)
    182		return ret;
    183
    184	return 0;
    185}
    186
    187static int dmard06_resume(struct device *dev)
    188{
    189	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
    190	struct dmard06_data *dmard06 = iio_priv(indio_dev);
    191	int ret;
    192
    193	ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
    194					DMARD06_MODE_NORMAL);
    195	if (ret < 0)
    196		return ret;
    197
    198	return 0;
    199}
    200
    201static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend,
    202				dmard06_resume);
    203
    204static const struct i2c_device_id dmard06_id[] = {
    205	{ "dmard05", 0 },
    206	{ "dmard06", 0 },
    207	{ "dmard07", 0 },
    208	{ }
    209};
    210MODULE_DEVICE_TABLE(i2c, dmard06_id);
    211
    212static const struct of_device_id dmard06_of_match[] = {
    213	{ .compatible = "domintech,dmard05" },
    214	{ .compatible = "domintech,dmard06" },
    215	{ .compatible = "domintech,dmard07" },
    216	{ }
    217};
    218MODULE_DEVICE_TABLE(of, dmard06_of_match);
    219
    220static struct i2c_driver dmard06_driver = {
    221	.probe = dmard06_probe,
    222	.id_table = dmard06_id,
    223	.driver = {
    224		.name = DMARD06_DRV_NAME,
    225		.of_match_table = dmard06_of_match,
    226		.pm = pm_sleep_ptr(&dmard06_pm_ops),
    227	},
    228};
    229module_i2c_driver(dmard06_driver);
    230
    231MODULE_AUTHOR("Aleksei Mamlin <mamlinav@gmail.com>");
    232MODULE_DESCRIPTION("Domintech DMARD06 accelerometer driver");
    233MODULE_LICENSE("GPL v2");