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_light_prox.c (7131B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * cros_ec_light_prox - Driver for light and prox sensors behing CrosEC.
      4 *
      5 * Copyright (C) 2017 Google, Inc
      6 */
      7
      8#include <linux/device.h>
      9#include <linux/iio/buffer.h>
     10#include <linux/iio/common/cros_ec_sensors_core.h>
     11#include <linux/iio/iio.h>
     12#include <linux/iio/kfifo_buf.h>
     13#include <linux/iio/trigger.h>
     14#include <linux/iio/triggered_buffer.h>
     15#include <linux/iio/trigger_consumer.h>
     16#include <linux/kernel.h>
     17#include <linux/module.h>
     18#include <linux/platform_data/cros_ec_commands.h>
     19#include <linux/platform_data/cros_ec_proto.h>
     20#include <linux/platform_device.h>
     21#include <linux/slab.h>
     22
     23/*
     24 * We only represent one entry for light or proximity. EC is merging different
     25 * light sensors to return the what the eye would see. For proximity, we
     26 * currently support only one light source.
     27 */
     28#define CROS_EC_LIGHT_PROX_MAX_CHANNELS (1 + 1)
     29
     30/* State data for ec_sensors iio driver. */
     31struct cros_ec_light_prox_state {
     32	/* Shared by all sensors */
     33	struct cros_ec_sensors_core_state core;
     34
     35	struct iio_chan_spec channels[CROS_EC_LIGHT_PROX_MAX_CHANNELS];
     36};
     37
     38static int cros_ec_light_prox_read(struct iio_dev *indio_dev,
     39				   struct iio_chan_spec const *chan,
     40				   int *val, int *val2, long mask)
     41{
     42	struct cros_ec_light_prox_state *st = iio_priv(indio_dev);
     43	u16 data = 0;
     44	s64 val64;
     45	int ret;
     46	int idx = chan->scan_index;
     47
     48	mutex_lock(&st->core.cmd_lock);
     49
     50	switch (mask) {
     51	case IIO_CHAN_INFO_RAW:
     52		if (chan->type == IIO_PROXIMITY) {
     53			ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
     54						     (s16 *)&data);
     55			if (ret)
     56				break;
     57			*val = data;
     58			ret = IIO_VAL_INT;
     59		} else {
     60			ret = -EINVAL;
     61		}
     62		break;
     63	case IIO_CHAN_INFO_PROCESSED:
     64		if (chan->type == IIO_LIGHT) {
     65			ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
     66						     (s16 *)&data);
     67			if (ret)
     68				break;
     69			/*
     70			 * The data coming from the light sensor is
     71			 * pre-processed and represents the ambient light
     72			 * illuminance reading expressed in lux.
     73			 */
     74			*val = data;
     75			ret = IIO_VAL_INT;
     76		} else {
     77			ret = -EINVAL;
     78		}
     79		break;
     80	case IIO_CHAN_INFO_CALIBBIAS:
     81		st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
     82		st->core.param.sensor_offset.flags = 0;
     83
     84		ret = cros_ec_motion_send_host_cmd(&st->core, 0);
     85		if (ret)
     86			break;
     87
     88		/* Save values */
     89		st->core.calib[0].offset =
     90			st->core.resp->sensor_offset.offset[0];
     91
     92		*val = st->core.calib[idx].offset;
     93		ret = IIO_VAL_INT;
     94		break;
     95	case IIO_CHAN_INFO_CALIBSCALE:
     96		/*
     97		 * RANGE is used for calibration
     98		 * scale is a number x.y, where x is coded on 16 bits,
     99		 * y coded on 16 bits, between 0 and 9999.
    100		 */
    101		st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
    102		st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE;
    103
    104		ret = cros_ec_motion_send_host_cmd(&st->core, 0);
    105		if (ret)
    106			break;
    107
    108		val64 = st->core.resp->sensor_range.ret;
    109		*val = val64 >> 16;
    110		*val2 = (val64 & 0xffff) * 100;
    111		ret = IIO_VAL_INT_PLUS_MICRO;
    112		break;
    113	default:
    114		ret = cros_ec_sensors_core_read(&st->core, chan, val, val2,
    115						mask);
    116		break;
    117	}
    118
    119	mutex_unlock(&st->core.cmd_lock);
    120
    121	return ret;
    122}
    123
    124static int cros_ec_light_prox_write(struct iio_dev *indio_dev,
    125			       struct iio_chan_spec const *chan,
    126			       int val, int val2, long mask)
    127{
    128	struct cros_ec_light_prox_state *st = iio_priv(indio_dev);
    129	int ret;
    130	int idx = chan->scan_index;
    131
    132	mutex_lock(&st->core.cmd_lock);
    133
    134	switch (mask) {
    135	case IIO_CHAN_INFO_CALIBBIAS:
    136		st->core.calib[idx].offset = val;
    137		/* Send to EC for each axis, even if not complete */
    138		st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
    139		st->core.param.sensor_offset.flags = MOTION_SENSE_SET_OFFSET;
    140		st->core.param.sensor_offset.offset[0] =
    141			st->core.calib[0].offset;
    142		st->core.param.sensor_offset.temp =
    143					EC_MOTION_SENSE_INVALID_CALIB_TEMP;
    144		ret = cros_ec_motion_send_host_cmd(&st->core, 0);
    145		break;
    146	case IIO_CHAN_INFO_CALIBSCALE:
    147		st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
    148		st->core.curr_range = (val << 16) | (val2 / 100);
    149		st->core.param.sensor_range.data = st->core.curr_range;
    150		ret = cros_ec_motion_send_host_cmd(&st->core, 0);
    151		if (ret == 0)
    152			st->core.range_updated = true;
    153		break;
    154	default:
    155		ret = cros_ec_sensors_core_write(&st->core, chan, val, val2,
    156						 mask);
    157		break;
    158	}
    159
    160	mutex_unlock(&st->core.cmd_lock);
    161
    162	return ret;
    163}
    164
    165static const struct iio_info cros_ec_light_prox_info = {
    166	.read_raw = &cros_ec_light_prox_read,
    167	.write_raw = &cros_ec_light_prox_write,
    168	.read_avail = &cros_ec_sensors_core_read_avail,
    169};
    170
    171static int cros_ec_light_prox_probe(struct platform_device *pdev)
    172{
    173	struct device *dev = &pdev->dev;
    174	struct iio_dev *indio_dev;
    175	struct cros_ec_light_prox_state *state;
    176	struct iio_chan_spec *channel;
    177	int ret;
    178
    179	indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
    180	if (!indio_dev)
    181		return -ENOMEM;
    182
    183	ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
    184					cros_ec_sensors_capture,
    185					cros_ec_sensors_push_data);
    186	if (ret)
    187		return ret;
    188
    189	indio_dev->info = &cros_ec_light_prox_info;
    190	state = iio_priv(indio_dev);
    191	state->core.type = state->core.resp->info.type;
    192	state->core.loc = state->core.resp->info.location;
    193	channel = state->channels;
    194
    195	/* Common part */
    196	channel->info_mask_shared_by_all =
    197		BIT(IIO_CHAN_INFO_SAMP_FREQ);
    198	channel->info_mask_shared_by_all_available =
    199		BIT(IIO_CHAN_INFO_SAMP_FREQ);
    200	channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
    201	channel->scan_type.storagebits = CROS_EC_SENSOR_BITS;
    202	channel->scan_type.shift = 0;
    203	channel->scan_index = 0;
    204	channel->ext_info = cros_ec_sensors_ext_info;
    205	channel->scan_type.sign = 'u';
    206
    207	/* Sensor specific */
    208	switch (state->core.type) {
    209	case MOTIONSENSE_TYPE_LIGHT:
    210		channel->type = IIO_LIGHT;
    211		channel->info_mask_separate =
    212			BIT(IIO_CHAN_INFO_PROCESSED) |
    213			BIT(IIO_CHAN_INFO_CALIBBIAS) |
    214			BIT(IIO_CHAN_INFO_CALIBSCALE);
    215		break;
    216	case MOTIONSENSE_TYPE_PROX:
    217		channel->type = IIO_PROXIMITY;
    218		channel->info_mask_separate =
    219			BIT(IIO_CHAN_INFO_RAW) |
    220			BIT(IIO_CHAN_INFO_CALIBBIAS) |
    221			BIT(IIO_CHAN_INFO_CALIBSCALE);
    222		break;
    223	default:
    224		dev_warn(dev, "Unknown motion sensor\n");
    225		return -EINVAL;
    226	}
    227
    228	/* Timestamp */
    229	channel++;
    230	channel->type = IIO_TIMESTAMP;
    231	channel->channel = -1;
    232	channel->scan_index = 1;
    233	channel->scan_type.sign = 's';
    234	channel->scan_type.realbits = 64;
    235	channel->scan_type.storagebits = 64;
    236
    237	indio_dev->channels = state->channels;
    238
    239	indio_dev->num_channels = CROS_EC_LIGHT_PROX_MAX_CHANNELS;
    240
    241	state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
    242
    243	return devm_iio_device_register(dev, indio_dev);
    244}
    245
    246static const struct platform_device_id cros_ec_light_prox_ids[] = {
    247	{
    248		.name = "cros-ec-prox",
    249	},
    250	{
    251		.name = "cros-ec-light",
    252	},
    253	{ /* sentinel */ }
    254};
    255MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids);
    256
    257static struct platform_driver cros_ec_light_prox_platform_driver = {
    258	.driver = {
    259		.name	= "cros-ec-light-prox",
    260		.pm	= &cros_ec_sensors_pm_ops,
    261	},
    262	.probe		= cros_ec_light_prox_probe,
    263	.id_table	= cros_ec_light_prox_ids,
    264};
    265module_platform_driver(cros_ec_light_prox_platform_driver);
    266
    267MODULE_DESCRIPTION("ChromeOS EC light/proximity sensors driver");
    268MODULE_LICENSE("GPL v2");