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

sps30_serial.c (10789B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Sensirion SPS30 particulate matter sensor serial driver
      4 *
      5 * Copyright (c) 2021 Tomasz Duszynski <tomasz.duszynski@octakon.com>
      6 */
      7#include <linux/completion.h>
      8#include <linux/device.h>
      9#include <linux/errno.h>
     10#include <linux/iio/iio.h>
     11#include <linux/minmax.h>
     12#include <linux/mod_devicetable.h>
     13#include <linux/module.h>
     14#include <linux/serdev.h>
     15#include <linux/types.h>
     16
     17#include "sps30.h"
     18
     19#define SPS30_SERIAL_DEV_NAME "sps30"
     20
     21#define SPS30_SERIAL_SOF_EOF 0x7e
     22#define SPS30_SERIAL_TIMEOUT msecs_to_jiffies(20)
     23#define SPS30_SERIAL_MAX_BUF_SIZE 263
     24#define SPS30_SERIAL_ESCAPE_CHAR 0x7d
     25
     26#define SPS30_SERIAL_FRAME_MIN_SIZE 7
     27#define SPS30_SERIAL_FRAME_ADR_OFFSET 1
     28#define SPS30_SERIAL_FRAME_CMD_OFFSET 2
     29#define SPS30_SERIAL_FRAME_MOSI_LEN_OFFSET 3
     30#define SPS30_SERIAL_FRAME_MISO_STATE_OFFSET 3
     31#define SPS30_SERIAL_FRAME_MISO_LEN_OFFSET 4
     32#define SPS30_SERIAL_FRAME_MISO_DATA_OFFSET 5
     33
     34#define SPS30_SERIAL_START_MEAS 0x00
     35#define SPS30_SERIAL_STOP_MEAS 0x01
     36#define SPS30_SERIAL_READ_MEAS 0x03
     37#define SPS30_SERIAL_RESET 0xd3
     38#define SPS30_SERIAL_CLEAN_FAN 0x56
     39#define SPS30_SERIAL_PERIOD 0x80
     40#define SPS30_SERIAL_DEV_INFO 0xd0
     41#define SPS30_SERIAL_READ_VERSION 0xd1
     42
     43struct sps30_serial_priv {
     44	struct completion new_frame;
     45	unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE];
     46	size_t num;
     47	bool escaped;
     48	bool done;
     49};
     50
     51static int sps30_serial_xfer(struct sps30_state *state, const unsigned char *buf, size_t size)
     52{
     53	struct serdev_device *serdev = to_serdev_device(state->dev);
     54	struct sps30_serial_priv *priv = state->priv;
     55	int ret;
     56
     57	priv->num = 0;
     58	priv->escaped = false;
     59	priv->done = false;
     60
     61	ret = serdev_device_write(serdev, buf, size, SPS30_SERIAL_TIMEOUT);
     62	if (ret < 0)
     63		return ret;
     64	if (ret != size)
     65		return -EIO;
     66
     67	ret = wait_for_completion_interruptible_timeout(&priv->new_frame, SPS30_SERIAL_TIMEOUT);
     68	if (ret < 0)
     69		return ret;
     70	if (!ret)
     71		return -ETIMEDOUT;
     72
     73	return 0;
     74}
     75
     76static const struct {
     77	unsigned char byte;
     78	unsigned char byte2;
     79} sps30_serial_bytes[] = {
     80	{ 0x11, 0x31 },
     81	{ 0x13, 0x33 },
     82	{ 0x7e, 0x5e },
     83	{ 0x7d, 0x5d },
     84};
     85
     86static int sps30_serial_put_byte(unsigned char *buf, unsigned char byte)
     87{
     88	int i;
     89
     90	for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) {
     91		if (sps30_serial_bytes[i].byte != byte)
     92			continue;
     93
     94		buf[0] = SPS30_SERIAL_ESCAPE_CHAR;
     95		buf[1] = sps30_serial_bytes[i].byte2;
     96
     97		return 2;
     98	}
     99
    100	buf[0] = byte;
    101
    102	return 1;
    103}
    104
    105static char sps30_serial_get_byte(bool escaped, unsigned char byte2)
    106{
    107	int i;
    108
    109	if (!escaped)
    110		return byte2;
    111
    112	for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) {
    113		if (sps30_serial_bytes[i].byte2 != byte2)
    114			continue;
    115
    116		return sps30_serial_bytes[i].byte;
    117	}
    118
    119	return 0;
    120}
    121
    122static unsigned char sps30_serial_calc_chksum(const unsigned char *buf, size_t num)
    123{
    124	unsigned int chksum = 0;
    125	size_t i;
    126
    127	for (i = 0; i < num; i++)
    128		chksum += buf[i];
    129
    130	return ~chksum;
    131}
    132
    133static int sps30_serial_prep_frame(unsigned char *buf, unsigned char cmd,
    134				   const unsigned char *arg, size_t arg_size)
    135{
    136	unsigned char chksum;
    137	int num = 0;
    138	size_t i;
    139
    140	buf[num++] = SPS30_SERIAL_SOF_EOF;
    141	buf[num++] = 0;
    142	num += sps30_serial_put_byte(buf + num, cmd);
    143	num += sps30_serial_put_byte(buf + num, arg_size);
    144
    145	for (i = 0; i < arg_size; i++)
    146		num += sps30_serial_put_byte(buf + num, arg[i]);
    147
    148	/* SOF isn't checksummed */
    149	chksum = sps30_serial_calc_chksum(buf + 1, num - 1);
    150	num += sps30_serial_put_byte(buf + num, chksum);
    151	buf[num++] = SPS30_SERIAL_SOF_EOF;
    152
    153	return num;
    154}
    155
    156static bool sps30_serial_frame_valid(struct sps30_state *state, const unsigned char *buf)
    157{
    158	struct sps30_serial_priv *priv = state->priv;
    159	unsigned char chksum;
    160
    161	if ((priv->num < SPS30_SERIAL_FRAME_MIN_SIZE) ||
    162	    (priv->num != SPS30_SERIAL_FRAME_MIN_SIZE +
    163	     priv->buf[SPS30_SERIAL_FRAME_MISO_LEN_OFFSET])) {
    164		dev_err(state->dev, "frame has invalid number of bytes\n");
    165		return false;
    166	}
    167
    168	if ((priv->buf[SPS30_SERIAL_FRAME_ADR_OFFSET] != buf[SPS30_SERIAL_FRAME_ADR_OFFSET]) ||
    169	    (priv->buf[SPS30_SERIAL_FRAME_CMD_OFFSET] != buf[SPS30_SERIAL_FRAME_CMD_OFFSET])) {
    170		dev_err(state->dev, "frame has wrong ADR and CMD bytes\n");
    171		return false;
    172	}
    173
    174	if (priv->buf[SPS30_SERIAL_FRAME_MISO_STATE_OFFSET]) {
    175		dev_err(state->dev, "frame with non-zero state received (0x%02x)\n",
    176			priv->buf[SPS30_SERIAL_FRAME_MISO_STATE_OFFSET]);
    177		return false;
    178	}
    179
    180	/* SOF, checksum and EOF are not checksummed */
    181	chksum = sps30_serial_calc_chksum(priv->buf + 1, priv->num - 3);
    182	if (priv->buf[priv->num - 2] != chksum) {
    183		dev_err(state->dev, "frame integrity check failed\n");
    184		return false;
    185	}
    186
    187	return true;
    188}
    189
    190static int sps30_serial_command(struct sps30_state *state, unsigned char cmd,
    191				const void *arg, size_t arg_size, void *rsp, size_t rsp_size)
    192{
    193	struct sps30_serial_priv *priv = state->priv;
    194	unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE];
    195	int ret, size;
    196
    197	size = sps30_serial_prep_frame(buf, cmd, arg, arg_size);
    198	ret = sps30_serial_xfer(state, buf, size);
    199	if (ret)
    200		return ret;
    201
    202	if (!sps30_serial_frame_valid(state, buf))
    203		return -EIO;
    204
    205	if (rsp) {
    206		rsp_size = min_t(size_t, priv->buf[SPS30_SERIAL_FRAME_MISO_LEN_OFFSET], rsp_size);
    207		memcpy(rsp, &priv->buf[SPS30_SERIAL_FRAME_MISO_DATA_OFFSET], rsp_size);
    208	}
    209
    210	return rsp_size;
    211}
    212
    213static int sps30_serial_receive_buf(struct serdev_device *serdev,
    214				    const unsigned char *buf, size_t size)
    215{
    216	struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
    217	struct sps30_serial_priv *priv;
    218	struct sps30_state *state;
    219	unsigned char byte;
    220	size_t i;
    221
    222	if (!indio_dev)
    223		return 0;
    224
    225	state = iio_priv(indio_dev);
    226	priv = state->priv;
    227
    228	/* just in case device put some unexpected data on the bus */
    229	if (priv->done)
    230		return size;
    231
    232	/* wait for the start of frame */
    233	if (!priv->num && size && buf[0] != SPS30_SERIAL_SOF_EOF)
    234		return 1;
    235
    236	if (priv->num + size >= ARRAY_SIZE(priv->buf))
    237		size = ARRAY_SIZE(priv->buf) - priv->num;
    238
    239	for (i = 0; i < size; i++) {
    240		byte = buf[i];
    241		/* remove stuffed bytes on-the-fly */
    242		if (byte == SPS30_SERIAL_ESCAPE_CHAR) {
    243			priv->escaped = true;
    244			continue;
    245		}
    246
    247		byte = sps30_serial_get_byte(priv->escaped, byte);
    248		if (priv->escaped && !byte)
    249			dev_warn(state->dev, "unrecognized escaped char (0x%02x)\n", byte);
    250
    251		priv->buf[priv->num++] = byte;
    252
    253		/* EOF received */
    254		if (!priv->escaped && byte == SPS30_SERIAL_SOF_EOF) {
    255			if (priv->num < SPS30_SERIAL_FRAME_MIN_SIZE)
    256				continue;
    257
    258			priv->done = true;
    259			complete(&priv->new_frame);
    260			i++;
    261			break;
    262		}
    263
    264		priv->escaped = false;
    265	}
    266
    267	return i;
    268}
    269
    270static const struct serdev_device_ops sps30_serial_device_ops = {
    271	.receive_buf = sps30_serial_receive_buf,
    272	.write_wakeup = serdev_device_write_wakeup,
    273};
    274
    275static int sps30_serial_start_meas(struct sps30_state *state)
    276{
    277	/* request BE IEEE754 formatted data */
    278	unsigned char buf[] = { 0x01, 0x03 };
    279
    280	return sps30_serial_command(state, SPS30_SERIAL_START_MEAS, buf, sizeof(buf), NULL, 0);
    281}
    282
    283static int sps30_serial_stop_meas(struct sps30_state *state)
    284{
    285	return sps30_serial_command(state, SPS30_SERIAL_STOP_MEAS, NULL, 0, NULL, 0);
    286}
    287
    288static int sps30_serial_reset(struct sps30_state *state)
    289{
    290	int ret;
    291
    292	ret = sps30_serial_command(state, SPS30_SERIAL_RESET, NULL, 0, NULL, 0);
    293	msleep(500);
    294
    295	return ret;
    296}
    297
    298static int sps30_serial_read_meas(struct sps30_state *state, __be32 *meas, size_t num)
    299{
    300	int ret;
    301
    302	/* measurements are ready within a second */
    303	if (msleep_interruptible(1000))
    304		return -EINTR;
    305
    306	ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, 0, meas, num * sizeof(num));
    307	if (ret < 0)
    308		return ret;
    309	/* if measurements aren't ready sensor returns empty frame */
    310	if (ret == SPS30_SERIAL_FRAME_MIN_SIZE)
    311		return -ETIMEDOUT;
    312	if (ret != num * sizeof(*meas))
    313		return -EIO;
    314
    315	return 0;
    316}
    317
    318static int sps30_serial_clean_fan(struct sps30_state *state)
    319{
    320	return sps30_serial_command(state, SPS30_SERIAL_CLEAN_FAN, NULL, 0, NULL, 0);
    321}
    322
    323static int sps30_serial_read_cleaning_period(struct sps30_state *state, __be32 *period)
    324{
    325	unsigned char buf[] = { 0x00 };
    326	int ret;
    327
    328	ret = sps30_serial_command(state, SPS30_SERIAL_PERIOD, buf, sizeof(buf),
    329				   period, sizeof(*period));
    330	if (ret < 0)
    331		return ret;
    332	if (ret != sizeof(*period))
    333		return -EIO;
    334
    335	return 0;
    336}
    337
    338static int sps30_serial_write_cleaning_period(struct sps30_state *state, __be32 period)
    339{
    340	unsigned char buf[5] = { 0x00 };
    341
    342	memcpy(buf + 1, &period, sizeof(period));
    343
    344	return sps30_serial_command(state, SPS30_SERIAL_PERIOD, buf, sizeof(buf), NULL, 0);
    345}
    346
    347static int sps30_serial_show_info(struct sps30_state *state)
    348{
    349	/*
    350	 * tell device do return serial number and add extra nul byte just in case
    351	 * serial number isn't a valid string
    352	 */
    353	unsigned char buf[32 + 1] = { 0x03 };
    354	struct device *dev = state->dev;
    355	int ret;
    356
    357	ret = sps30_serial_command(state, SPS30_SERIAL_DEV_INFO, buf, 1, buf, sizeof(buf) - 1);
    358	if (ret < 0)
    359		return ret;
    360	if (ret != sizeof(buf) - 1)
    361		return -EIO;
    362
    363	dev_info(dev, "serial number: %s\n", buf);
    364
    365	ret = sps30_serial_command(state, SPS30_SERIAL_READ_VERSION, NULL, 0, buf, sizeof(buf) - 1);
    366	if (ret < 0)
    367		return ret;
    368	if (ret < 2)
    369		return -EIO;
    370
    371	dev_info(dev, "fw version: %u.%u\n", buf[0], buf[1]);
    372
    373	return 0;
    374}
    375
    376static const struct sps30_ops sps30_serial_ops = {
    377	.start_meas = sps30_serial_start_meas,
    378	.stop_meas = sps30_serial_stop_meas,
    379	.read_meas = sps30_serial_read_meas,
    380	.reset = sps30_serial_reset,
    381	.clean_fan = sps30_serial_clean_fan,
    382	.read_cleaning_period = sps30_serial_read_cleaning_period,
    383	.write_cleaning_period = sps30_serial_write_cleaning_period,
    384	.show_info = sps30_serial_show_info,
    385};
    386
    387static int sps30_serial_probe(struct serdev_device *serdev)
    388{
    389	struct device *dev = &serdev->dev;
    390	struct sps30_serial_priv *priv;
    391	int ret;
    392
    393	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    394	if (!priv)
    395		return -ENOMEM;
    396
    397	init_completion(&priv->new_frame);
    398	serdev_device_set_client_ops(serdev, &sps30_serial_device_ops);
    399
    400	ret = devm_serdev_device_open(dev, serdev);
    401	if (ret)
    402		return ret;
    403
    404	serdev_device_set_baudrate(serdev, 115200);
    405	serdev_device_set_flow_control(serdev, false);
    406
    407	ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
    408	if (ret)
    409		return ret;
    410
    411	return sps30_probe(dev, SPS30_SERIAL_DEV_NAME, priv, &sps30_serial_ops);
    412}
    413
    414static const struct of_device_id sps30_serial_of_match[] = {
    415	{ .compatible = "sensirion,sps30" },
    416	{ }
    417};
    418MODULE_DEVICE_TABLE(of, sps30_serial_of_match);
    419
    420static struct serdev_device_driver sps30_serial_driver = {
    421	.driver = {
    422		.name = KBUILD_MODNAME,
    423		.of_match_table = sps30_serial_of_match,
    424	},
    425	.probe = sps30_serial_probe,
    426};
    427module_serdev_device_driver(sps30_serial_driver);
    428
    429MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
    430MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver");
    431MODULE_LICENSE("GPL v2");