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

dmard10.c (6566B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * IIO driver for the 3-axis accelerometer Domintech ARD10.
      4 *
      5 * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
      6 * Copyright (c) 2012 Domintech Technology Co., Ltd
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/i2c.h>
     11#include <linux/iio/iio.h>
     12#include <linux/iio/sysfs.h>
     13#include <linux/byteorder/generic.h>
     14
     15#define DMARD10_REG_ACTR			0x00
     16#define DMARD10_REG_AFEM			0x0c
     17#define DMARD10_REG_STADR			0x12
     18#define DMARD10_REG_STAINT			0x1c
     19#define DMARD10_REG_MISC2			0x1f
     20#define DMARD10_REG_PD				0x21
     21
     22#define DMARD10_MODE_OFF			0x00
     23#define DMARD10_MODE_STANDBY			0x02
     24#define DMARD10_MODE_ACTIVE			0x06
     25#define DMARD10_MODE_READ_OTP			0x12
     26#define DMARD10_MODE_RESET_DATA_PATH		0x82
     27
     28/* AFEN set 1, ATM[2:0]=b'000 (normal), EN_Z/Y/X/T=1 */
     29#define DMARD10_VALUE_AFEM_AFEN_NORMAL		0x8f
     30/* ODR[3:0]=b'0111 (100Hz), CCK[3:0]=b'0100 (204.8kHZ) */
     31#define DMARD10_VALUE_CKSEL_ODR_100_204		0x74
     32/* INTC[6:5]=b'00 */
     33#define DMARD10_VALUE_INTC			0x00
     34/* TAP1/TAP2 Average 2 */
     35#define DMARD10_VALUE_TAPNS_AVE_2		0x11
     36
     37#define DMARD10_VALUE_STADR			0x55
     38#define DMARD10_VALUE_STAINT			0xaa
     39#define DMARD10_VALUE_MISC2_OSCA_EN		0x08
     40#define DMARD10_VALUE_PD_RST			0x52
     41
     42/* Offsets into the buffer read in dmard10_read_raw() */
     43#define DMARD10_X_OFFSET			1
     44#define DMARD10_Y_OFFSET			2
     45#define DMARD10_Z_OFFSET			3
     46
     47/*
     48 * a value of + or -128 corresponds to + or - 1G
     49 * scale = 9.81 / 128 = 0.076640625
     50 */
     51
     52static const int dmard10_nscale = 76640625;
     53
     54#define DMARD10_CHANNEL(reg, axis) {	\
     55	.type = IIO_ACCEL,	\
     56	.address = reg,	\
     57	.modified = 1,	\
     58	.channel2 = IIO_MOD_##axis,	\
     59	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
     60	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
     61}
     62
     63static const struct iio_chan_spec dmard10_channels[] = {
     64	DMARD10_CHANNEL(DMARD10_X_OFFSET, X),
     65	DMARD10_CHANNEL(DMARD10_Y_OFFSET, Y),
     66	DMARD10_CHANNEL(DMARD10_Z_OFFSET, Z),
     67};
     68
     69struct dmard10_data {
     70	struct i2c_client *client;
     71};
     72
     73/* Init sequence taken from the android driver */
     74static int dmard10_reset(struct i2c_client *client)
     75{
     76	unsigned char buffer[7];
     77	int ret;
     78
     79	/* 1. Powerdown reset */
     80	ret = i2c_smbus_write_byte_data(client, DMARD10_REG_PD,
     81						DMARD10_VALUE_PD_RST);
     82	if (ret < 0)
     83		return ret;
     84
     85	/*
     86	 * 2. ACTR => Standby mode => Download OTP to parameter reg =>
     87	 *    Standby mode => Reset data path => Standby mode
     88	 */
     89	buffer[0] = DMARD10_REG_ACTR;
     90	buffer[1] = DMARD10_MODE_STANDBY;
     91	buffer[2] = DMARD10_MODE_READ_OTP;
     92	buffer[3] = DMARD10_MODE_STANDBY;
     93	buffer[4] = DMARD10_MODE_RESET_DATA_PATH;
     94	buffer[5] = DMARD10_MODE_STANDBY;
     95	ret = i2c_master_send(client, buffer, 6);
     96	if (ret < 0)
     97		return ret;
     98
     99	/* 3. OSCA_EN = 1, TSTO = b'000 (INT1 = normal, TEST0 = normal) */
    100	ret = i2c_smbus_write_byte_data(client, DMARD10_REG_MISC2,
    101						DMARD10_VALUE_MISC2_OSCA_EN);
    102	if (ret < 0)
    103		return ret;
    104
    105	/* 4. AFEN = 1 (AFE will powerdown after ADC) */
    106	buffer[0] = DMARD10_REG_AFEM;
    107	buffer[1] = DMARD10_VALUE_AFEM_AFEN_NORMAL;
    108	buffer[2] = DMARD10_VALUE_CKSEL_ODR_100_204;
    109	buffer[3] = DMARD10_VALUE_INTC;
    110	buffer[4] = DMARD10_VALUE_TAPNS_AVE_2;
    111	buffer[5] = 0x00; /* DLYC, no delay timing */
    112	buffer[6] = 0x07; /* INTD=1 push-pull, INTA=1 active high, AUTOT=1 */
    113	ret = i2c_master_send(client, buffer, 7);
    114	if (ret < 0)
    115		return ret;
    116
    117	/* 5. Activation mode */
    118	ret = i2c_smbus_write_byte_data(client, DMARD10_REG_ACTR,
    119						DMARD10_MODE_ACTIVE);
    120	if (ret < 0)
    121		return ret;
    122
    123	return 0;
    124}
    125
    126/* Shutdown sequence taken from the android driver */
    127static int dmard10_shutdown(struct i2c_client *client)
    128{
    129	unsigned char buffer[3];
    130
    131	buffer[0] = DMARD10_REG_ACTR;
    132	buffer[1] = DMARD10_MODE_STANDBY;
    133	buffer[2] = DMARD10_MODE_OFF;
    134
    135	return i2c_master_send(client, buffer, 3);
    136}
    137
    138static int dmard10_read_raw(struct iio_dev *indio_dev,
    139				struct iio_chan_spec const *chan,
    140				int *val, int *val2, long mask)
    141{
    142	struct dmard10_data *data = iio_priv(indio_dev);
    143	__le16 buf[4];
    144	int ret;
    145
    146	switch (mask) {
    147	case IIO_CHAN_INFO_RAW:
    148		/*
    149		 * Read 8 bytes starting at the REG_STADR register, trying to
    150		 * read the individual X, Y, Z registers will always read 0.
    151		 */
    152		ret = i2c_smbus_read_i2c_block_data(data->client,
    153						    DMARD10_REG_STADR,
    154						    sizeof(buf), (u8 *)buf);
    155		if (ret < 0)
    156			return ret;
    157		ret = le16_to_cpu(buf[chan->address]);
    158		*val = sign_extend32(ret, 12);
    159		return IIO_VAL_INT;
    160	case IIO_CHAN_INFO_SCALE:
    161		*val = 0;
    162		*val2 = dmard10_nscale;
    163		return IIO_VAL_INT_PLUS_NANO;
    164	default:
    165		return -EINVAL;
    166	}
    167}
    168
    169static const struct iio_info dmard10_info = {
    170	.read_raw	= dmard10_read_raw,
    171};
    172
    173static void dmard10_shutdown_cleanup(void *client)
    174{
    175	dmard10_shutdown(client);
    176}
    177
    178static int dmard10_probe(struct i2c_client *client,
    179			const struct i2c_device_id *id)
    180{
    181	int ret;
    182	struct iio_dev *indio_dev;
    183	struct dmard10_data *data;
    184
    185	/* These 2 registers have special POR reset values used for id */
    186	ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STADR);
    187	if (ret != DMARD10_VALUE_STADR)
    188		return (ret < 0) ? ret : -ENODEV;
    189
    190	ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STAINT);
    191	if (ret != DMARD10_VALUE_STAINT)
    192		return (ret < 0) ? ret : -ENODEV;
    193
    194	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    195	if (!indio_dev) {
    196		dev_err(&client->dev, "iio allocation failed!\n");
    197		return -ENOMEM;
    198	}
    199
    200	data = iio_priv(indio_dev);
    201	data->client = client;
    202
    203	indio_dev->info = &dmard10_info;
    204	indio_dev->name = "dmard10";
    205	indio_dev->modes = INDIO_DIRECT_MODE;
    206	indio_dev->channels = dmard10_channels;
    207	indio_dev->num_channels = ARRAY_SIZE(dmard10_channels);
    208
    209	ret = dmard10_reset(client);
    210	if (ret < 0)
    211		return ret;
    212
    213	ret = devm_add_action_or_reset(&client->dev, dmard10_shutdown_cleanup,
    214				       client);
    215	if (ret)
    216		return ret;
    217
    218	return devm_iio_device_register(&client->dev, indio_dev);
    219}
    220
    221static int dmard10_suspend(struct device *dev)
    222{
    223	return dmard10_shutdown(to_i2c_client(dev));
    224}
    225
    226static int dmard10_resume(struct device *dev)
    227{
    228	return dmard10_reset(to_i2c_client(dev));
    229}
    230
    231static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend,
    232				dmard10_resume);
    233
    234static const struct i2c_device_id dmard10_i2c_id[] = {
    235	{"dmard10", 0},
    236	{}
    237};
    238MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id);
    239
    240static struct i2c_driver dmard10_driver = {
    241	.driver = {
    242		.name = "dmard10",
    243		.pm = pm_sleep_ptr(&dmard10_pm_ops),
    244	},
    245	.probe		= dmard10_probe,
    246	.id_table	= dmard10_i2c_id,
    247};
    248
    249module_i2c_driver(dmard10_driver);
    250
    251MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
    252MODULE_DESCRIPTION("Domintech ARD10 3-Axis Accelerometer driver");
    253MODULE_LICENSE("GPL v2");