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

da280.c (4516B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * IIO driver for the MiraMEMS DA280 3-axis accelerometer and
      4 * IIO driver for the MiraMEMS DA226 2-axis accelerometer
      5 *
      6 * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/i2c.h>
     11#include <linux/acpi.h>
     12#include <linux/iio/iio.h>
     13#include <linux/iio/sysfs.h>
     14#include <linux/byteorder/generic.h>
     15
     16#define DA280_REG_CHIP_ID		0x01
     17#define DA280_REG_ACC_X_LSB		0x02
     18#define DA280_REG_ACC_Y_LSB		0x04
     19#define DA280_REG_ACC_Z_LSB		0x06
     20#define DA280_REG_MODE_BW		0x11
     21
     22#define DA280_CHIP_ID			0x13
     23#define DA280_MODE_ENABLE		0x1e
     24#define DA280_MODE_DISABLE		0x9e
     25
     26enum da280_chipset { da226, da280 };
     27
     28/*
     29 * a value of + or -4096 corresponds to + or - 1G
     30 * scale = 9.81 / 4096 = 0.002395019
     31 */
     32
     33static const int da280_nscale = 2395019;
     34
     35#define DA280_CHANNEL(reg, axis) {	\
     36	.type = IIO_ACCEL,	\
     37	.address = reg,	\
     38	.modified = 1,	\
     39	.channel2 = IIO_MOD_##axis,	\
     40	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
     41	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
     42}
     43
     44static const struct iio_chan_spec da280_channels[] = {
     45	DA280_CHANNEL(DA280_REG_ACC_X_LSB, X),
     46	DA280_CHANNEL(DA280_REG_ACC_Y_LSB, Y),
     47	DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z),
     48};
     49
     50struct da280_data {
     51	struct i2c_client *client;
     52};
     53
     54static int da280_enable(struct i2c_client *client, bool enable)
     55{
     56	u8 data = enable ? DA280_MODE_ENABLE : DA280_MODE_DISABLE;
     57
     58	return i2c_smbus_write_byte_data(client, DA280_REG_MODE_BW, data);
     59}
     60
     61static int da280_read_raw(struct iio_dev *indio_dev,
     62				struct iio_chan_spec const *chan,
     63				int *val, int *val2, long mask)
     64{
     65	struct da280_data *data = iio_priv(indio_dev);
     66	int ret;
     67
     68	switch (mask) {
     69	case IIO_CHAN_INFO_RAW:
     70		ret = i2c_smbus_read_word_data(data->client, chan->address);
     71		if (ret < 0)
     72			return ret;
     73		/*
     74		 * Values are 14 bits, stored as 16 bits with the 2
     75		 * least significant bits always 0.
     76		 */
     77		*val = (short)ret >> 2;
     78		return IIO_VAL_INT;
     79	case IIO_CHAN_INFO_SCALE:
     80		*val = 0;
     81		*val2 = da280_nscale;
     82		return IIO_VAL_INT_PLUS_NANO;
     83	default:
     84		return -EINVAL;
     85	}
     86}
     87
     88static const struct iio_info da280_info = {
     89	.read_raw	= da280_read_raw,
     90};
     91
     92static enum da280_chipset da280_match_acpi_device(struct device *dev)
     93{
     94	const struct acpi_device_id *id;
     95
     96	id = acpi_match_device(dev->driver->acpi_match_table, dev);
     97	if (!id)
     98		return -EINVAL;
     99
    100	return (enum da280_chipset) id->driver_data;
    101}
    102
    103static void da280_disable(void *client)
    104{
    105	da280_enable(client, false);
    106}
    107
    108static int da280_probe(struct i2c_client *client,
    109			const struct i2c_device_id *id)
    110{
    111	int ret;
    112	struct iio_dev *indio_dev;
    113	struct da280_data *data;
    114	enum da280_chipset chip;
    115
    116	ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID);
    117	if (ret != DA280_CHIP_ID)
    118		return (ret < 0) ? ret : -ENODEV;
    119
    120	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    121	if (!indio_dev)
    122		return -ENOMEM;
    123
    124	data = iio_priv(indio_dev);
    125	data->client = client;
    126
    127	indio_dev->info = &da280_info;
    128	indio_dev->modes = INDIO_DIRECT_MODE;
    129	indio_dev->channels = da280_channels;
    130
    131	if (ACPI_HANDLE(&client->dev)) {
    132		chip = da280_match_acpi_device(&client->dev);
    133	} else {
    134		chip = id->driver_data;
    135	}
    136
    137	if (chip == da226) {
    138		indio_dev->name = "da226";
    139		indio_dev->num_channels = 2;
    140	} else {
    141		indio_dev->name = "da280";
    142		indio_dev->num_channels = 3;
    143	}
    144
    145	ret = da280_enable(client, true);
    146	if (ret < 0)
    147		return ret;
    148
    149	ret = devm_add_action_or_reset(&client->dev, da280_disable, client);
    150	if (ret)
    151		return ret;
    152
    153	return devm_iio_device_register(&client->dev, indio_dev);
    154}
    155
    156static int da280_suspend(struct device *dev)
    157{
    158	return da280_enable(to_i2c_client(dev), false);
    159}
    160
    161static int da280_resume(struct device *dev)
    162{
    163	return da280_enable(to_i2c_client(dev), true);
    164}
    165
    166static DEFINE_SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume);
    167
    168static const struct acpi_device_id da280_acpi_match[] = {
    169	{"MIRAACC", da280},
    170	{},
    171};
    172MODULE_DEVICE_TABLE(acpi, da280_acpi_match);
    173
    174static const struct i2c_device_id da280_i2c_id[] = {
    175	{ "da226", da226 },
    176	{ "da280", da280 },
    177	{}
    178};
    179MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
    180
    181static struct i2c_driver da280_driver = {
    182	.driver = {
    183		.name = "da280",
    184		.acpi_match_table = ACPI_PTR(da280_acpi_match),
    185		.pm = pm_sleep_ptr(&da280_pm_ops),
    186	},
    187	.probe		= da280_probe,
    188	.id_table	= da280_i2c_id,
    189};
    190
    191module_i2c_driver(da280_driver);
    192
    193MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
    194MODULE_DESCRIPTION("MiraMEMS DA280 3-Axis Accelerometer driver");
    195MODULE_LICENSE("GPL v2");