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

cros_ec_accel_legacy.c (7005B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Driver for older Chrome OS EC accelerometer
      4 *
      5 * Copyright 2017 Google, Inc
      6 *
      7 * This driver uses the memory mapper cros-ec interface to communicate
      8 * with the Chrome OS EC about accelerometer data or older commands.
      9 * Accelerometer access is presented through iio sysfs.
     10 */
     11
     12#include <linux/delay.h>
     13#include <linux/device.h>
     14#include <linux/iio/buffer.h>
     15#include <linux/iio/common/cros_ec_sensors_core.h>
     16#include <linux/iio/iio.h>
     17#include <linux/iio/kfifo_buf.h>
     18#include <linux/iio/trigger_consumer.h>
     19#include <linux/iio/triggered_buffer.h>
     20#include <linux/kernel.h>
     21#include <linux/module.h>
     22#include <linux/slab.h>
     23#include <linux/platform_data/cros_ec_commands.h>
     24#include <linux/platform_data/cros_ec_proto.h>
     25#include <linux/platform_device.h>
     26
     27#define DRV_NAME	"cros-ec-accel-legacy"
     28
     29#define CROS_EC_SENSOR_LEGACY_NUM 2
     30/*
     31 * Sensor scale hard coded at 10 bits per g, computed as:
     32 * g / (2^10 - 1) = 0.009586168; with g = 9.80665 m.s^-2
     33 */
     34#define ACCEL_LEGACY_NSCALE 9586168
     35
     36/*
     37 * Sensor frequency is hard-coded to 10Hz.
     38 */
     39static const int cros_ec_legacy_sample_freq[] = { 10, 0 };
     40
     41static int cros_ec_accel_legacy_read_cmd(struct iio_dev *indio_dev,
     42				  unsigned long scan_mask, s16 *data)
     43{
     44	struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
     45	int ret;
     46	unsigned int i;
     47	u8 sensor_num;
     48
     49	/*
     50	 * Read all sensor data through a command.
     51	 * Save sensor_num, it is assumed to stay.
     52	 */
     53	sensor_num = st->param.info.sensor_num;
     54	st->param.cmd = MOTIONSENSE_CMD_DUMP;
     55	st->param.dump.max_sensor_count = CROS_EC_SENSOR_LEGACY_NUM;
     56	ret = cros_ec_motion_send_host_cmd(st,
     57			sizeof(st->resp->dump) + CROS_EC_SENSOR_LEGACY_NUM *
     58			sizeof(struct ec_response_motion_sensor_data));
     59	st->param.info.sensor_num = sensor_num;
     60	if (ret != 0) {
     61		dev_warn(&indio_dev->dev, "Unable to read sensor data\n");
     62		return ret;
     63	}
     64
     65	for_each_set_bit(i, &scan_mask, indio_dev->masklength) {
     66		*data = st->resp->dump.sensor[sensor_num].data[i] *
     67			st->sign[i];
     68		data++;
     69	}
     70
     71	return 0;
     72}
     73
     74static int cros_ec_accel_legacy_read(struct iio_dev *indio_dev,
     75				     struct iio_chan_spec const *chan,
     76				     int *val, int *val2, long mask)
     77{
     78	struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
     79	s16 data = 0;
     80	int ret;
     81	int idx = chan->scan_index;
     82
     83	mutex_lock(&st->cmd_lock);
     84
     85	switch (mask) {
     86	case IIO_CHAN_INFO_RAW:
     87		ret = st->read_ec_sensors_data(indio_dev, 1 << idx, &data);
     88		if (ret < 0)
     89			break;
     90		ret = IIO_VAL_INT;
     91		*val = data;
     92		break;
     93	case IIO_CHAN_INFO_SCALE:
     94		WARN_ON(st->type != MOTIONSENSE_TYPE_ACCEL);
     95		*val = 0;
     96		*val2 = ACCEL_LEGACY_NSCALE;
     97		ret = IIO_VAL_INT_PLUS_NANO;
     98		break;
     99	case IIO_CHAN_INFO_CALIBBIAS:
    100		/* Calibration not supported. */
    101		*val = 0;
    102		ret = IIO_VAL_INT;
    103		break;
    104	case IIO_CHAN_INFO_SAMP_FREQ:
    105		*val = cros_ec_legacy_sample_freq[0];
    106		*val2 = cros_ec_legacy_sample_freq[1];
    107		ret = IIO_VAL_INT_PLUS_MICRO;
    108		break;
    109	default:
    110		ret = cros_ec_sensors_core_read(st, chan, val, val2,
    111				mask);
    112		break;
    113	}
    114	mutex_unlock(&st->cmd_lock);
    115
    116	return ret;
    117}
    118
    119static int cros_ec_accel_legacy_write(struct iio_dev *indio_dev,
    120				      struct iio_chan_spec const *chan,
    121				      int val, int val2, long mask)
    122{
    123	/*
    124	 * Do nothing but don't return an error code to allow calibration
    125	 * script to work.
    126	 */
    127	if (mask == IIO_CHAN_INFO_CALIBBIAS)
    128		return 0;
    129
    130	return -EINVAL;
    131}
    132
    133/**
    134 * cros_ec_accel_legacy_read_avail() - get available values
    135 * @indio_dev:		pointer to state information for device
    136 * @chan:	channel specification structure table
    137 * @vals:	list of available values
    138 * @type:	type of data returned
    139 * @length:	number of data returned in the array
    140 * @mask:	specifies which values to be requested
    141 *
    142 * Return:	an error code or IIO_AVAIL_LIST
    143 */
    144static int cros_ec_accel_legacy_read_avail(struct iio_dev *indio_dev,
    145					   struct iio_chan_spec const *chan,
    146					   const int **vals,
    147					   int *type,
    148					   int *length,
    149					   long mask)
    150{
    151	switch (mask) {
    152	case IIO_CHAN_INFO_SAMP_FREQ:
    153		*length = ARRAY_SIZE(cros_ec_legacy_sample_freq);
    154		*vals = cros_ec_legacy_sample_freq;
    155		*type = IIO_VAL_INT_PLUS_MICRO;
    156		return IIO_AVAIL_LIST;
    157	}
    158
    159	return -EINVAL;
    160}
    161
    162static const struct iio_info cros_ec_accel_legacy_info = {
    163	.read_raw = &cros_ec_accel_legacy_read,
    164	.write_raw = &cros_ec_accel_legacy_write,
    165	.read_avail = &cros_ec_accel_legacy_read_avail,
    166};
    167
    168/*
    169 * Present the channel using HTML5 standard:
    170 * need to invert X and Y and invert some lid axis.
    171 */
    172#define CROS_EC_ACCEL_ROTATE_AXIS(_axis)				\
    173	((_axis) == CROS_EC_SENSOR_Z ? CROS_EC_SENSOR_Z :		\
    174	 ((_axis) == CROS_EC_SENSOR_X ? CROS_EC_SENSOR_Y :		\
    175	  CROS_EC_SENSOR_X))
    176
    177#define CROS_EC_ACCEL_LEGACY_CHAN(_axis)				\
    178	{								\
    179		.type = IIO_ACCEL,					\
    180		.channel2 = IIO_MOD_X + (_axis),			\
    181		.modified = 1,					        \
    182		.info_mask_separate =					\
    183			BIT(IIO_CHAN_INFO_RAW) |			\
    184			BIT(IIO_CHAN_INFO_CALIBBIAS),			\
    185		.info_mask_shared_by_all =				\
    186			BIT(IIO_CHAN_INFO_SCALE) |			\
    187			BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
    188		.info_mask_shared_by_all_available =			\
    189			BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
    190		.ext_info = cros_ec_sensors_ext_info,			\
    191		.scan_type = {						\
    192			.sign = 's',					\
    193			.realbits = CROS_EC_SENSOR_BITS,		\
    194			.storagebits = CROS_EC_SENSOR_BITS,		\
    195		},							\
    196		.scan_index = CROS_EC_ACCEL_ROTATE_AXIS(_axis),		\
    197	}								\
    198
    199static const struct iio_chan_spec cros_ec_accel_legacy_channels[] = {
    200		CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_X),
    201		CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_Y),
    202		CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_Z),
    203		IIO_CHAN_SOFT_TIMESTAMP(CROS_EC_SENSOR_MAX_AXIS)
    204};
    205
    206static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
    207{
    208	struct device *dev = &pdev->dev;
    209	struct iio_dev *indio_dev;
    210	struct cros_ec_sensors_core_state *state;
    211	int ret;
    212
    213	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
    214	if (!indio_dev)
    215		return -ENOMEM;
    216
    217	ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
    218					cros_ec_sensors_capture, NULL);
    219	if (ret)
    220		return ret;
    221
    222	indio_dev->info = &cros_ec_accel_legacy_info;
    223	state = iio_priv(indio_dev);
    224
    225	if (state->ec->cmd_readmem != NULL)
    226		state->read_ec_sensors_data = cros_ec_sensors_read_lpc;
    227	else
    228		state->read_ec_sensors_data = cros_ec_accel_legacy_read_cmd;
    229
    230	indio_dev->channels = cros_ec_accel_legacy_channels;
    231	indio_dev->num_channels = ARRAY_SIZE(cros_ec_accel_legacy_channels);
    232	/* The lid sensor needs to be presented inverted. */
    233	if (state->loc == MOTIONSENSE_LOC_LID) {
    234		state->sign[CROS_EC_SENSOR_X] = -1;
    235		state->sign[CROS_EC_SENSOR_Z] = -1;
    236	}
    237
    238	return devm_iio_device_register(dev, indio_dev);
    239}
    240
    241static struct platform_driver cros_ec_accel_platform_driver = {
    242	.driver = {
    243		.name	= DRV_NAME,
    244	},
    245	.probe		= cros_ec_accel_legacy_probe,
    246};
    247module_platform_driver(cros_ec_accel_platform_driver);
    248
    249MODULE_DESCRIPTION("ChromeOS EC legacy accelerometer driver");
    250MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
    251MODULE_LICENSE("GPL v2");
    252MODULE_ALIAS("platform:" DRV_NAME);