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

ms5611_core.c (11094B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * MS5611 pressure and temperature sensor driver
      4 *
      5 * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
      6 *
      7 * Data sheet:
      8 *  http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
      9 *  http://www.meas-spec.com/downloads/MS5607-02BA03.pdf
     10 *
     11 */
     12
     13#include <linux/module.h>
     14#include <linux/iio/iio.h>
     15#include <linux/delay.h>
     16#include <linux/regulator/consumer.h>
     17
     18#include <linux/iio/sysfs.h>
     19#include <linux/iio/buffer.h>
     20#include <linux/iio/triggered_buffer.h>
     21#include <linux/iio/trigger_consumer.h>
     22#include "ms5611.h"
     23
     24#define MS5611_INIT_OSR(_cmd, _conv_usec, _rate) \
     25	{ .cmd = _cmd, .conv_usec = _conv_usec, .rate = _rate }
     26
     27static const struct ms5611_osr ms5611_avail_pressure_osr[] = {
     28	MS5611_INIT_OSR(0x40, 600,  256),
     29	MS5611_INIT_OSR(0x42, 1170, 512),
     30	MS5611_INIT_OSR(0x44, 2280, 1024),
     31	MS5611_INIT_OSR(0x46, 4540, 2048),
     32	MS5611_INIT_OSR(0x48, 9040, 4096)
     33};
     34
     35static const struct ms5611_osr ms5611_avail_temp_osr[] = {
     36	MS5611_INIT_OSR(0x50, 600,  256),
     37	MS5611_INIT_OSR(0x52, 1170, 512),
     38	MS5611_INIT_OSR(0x54, 2280, 1024),
     39	MS5611_INIT_OSR(0x56, 4540, 2048),
     40	MS5611_INIT_OSR(0x58, 9040, 4096)
     41};
     42
     43static const char ms5611_show_osr[] = "256 512 1024 2048 4096";
     44
     45static IIO_CONST_ATTR(oversampling_ratio_available, ms5611_show_osr);
     46
     47static struct attribute *ms5611_attributes[] = {
     48	&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
     49	NULL,
     50};
     51
     52static const struct attribute_group ms5611_attribute_group = {
     53	.attrs = ms5611_attributes,
     54};
     55
     56static bool ms5611_prom_is_valid(u16 *prom, size_t len)
     57{
     58	int i, j;
     59	uint16_t crc = 0, crc_orig = prom[7] & 0x000F;
     60
     61	prom[7] &= 0xFF00;
     62
     63	for (i = 0; i < len * 2; i++) {
     64		if (i % 2 == 1)
     65			crc ^= prom[i >> 1] & 0x00FF;
     66		else
     67			crc ^= prom[i >> 1] >> 8;
     68
     69		for (j = 0; j < 8; j++) {
     70			if (crc & 0x8000)
     71				crc = (crc << 1) ^ 0x3000;
     72			else
     73				crc <<= 1;
     74		}
     75	}
     76
     77	crc = (crc >> 12) & 0x000F;
     78
     79	return crc_orig != 0x0000 && crc == crc_orig;
     80}
     81
     82static int ms5611_read_prom(struct iio_dev *indio_dev)
     83{
     84	int ret, i;
     85	struct ms5611_state *st = iio_priv(indio_dev);
     86
     87	for (i = 0; i < MS5611_PROM_WORDS_NB; i++) {
     88		ret = st->read_prom_word(st, i, &st->chip_info->prom[i]);
     89		if (ret < 0) {
     90			dev_err(&indio_dev->dev,
     91				"failed to read prom at %d\n", i);
     92			return ret;
     93		}
     94	}
     95
     96	if (!ms5611_prom_is_valid(st->chip_info->prom, MS5611_PROM_WORDS_NB)) {
     97		dev_err(&indio_dev->dev, "PROM integrity check failed\n");
     98		return -ENODEV;
     99	}
    100
    101	return 0;
    102}
    103
    104static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
    105					 s32 *temp, s32 *pressure)
    106{
    107	int ret;
    108	struct ms5611_state *st = iio_priv(indio_dev);
    109
    110	ret = st->read_adc_temp_and_pressure(st, temp, pressure);
    111	if (ret < 0) {
    112		dev_err(&indio_dev->dev,
    113			"failed to read temperature and pressure\n");
    114		return ret;
    115	}
    116
    117	return st->chip_info->temp_and_pressure_compensate(st->chip_info,
    118							   temp, pressure);
    119}
    120
    121static int ms5611_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
    122					       s32 *temp, s32 *pressure)
    123{
    124	s32 t = *temp, p = *pressure;
    125	s64 off, sens, dt;
    126
    127	dt = t - (chip_info->prom[5] << 8);
    128	off = ((s64)chip_info->prom[2] << 16) + ((chip_info->prom[4] * dt) >> 7);
    129	sens = ((s64)chip_info->prom[1] << 15) + ((chip_info->prom[3] * dt) >> 8);
    130
    131	t = 2000 + ((chip_info->prom[6] * dt) >> 23);
    132	if (t < 2000) {
    133		s64 off2, sens2, t2;
    134
    135		t2 = (dt * dt) >> 31;
    136		off2 = (5 * (t - 2000) * (t - 2000)) >> 1;
    137		sens2 = off2 >> 1;
    138
    139		if (t < -1500) {
    140			s64 tmp = (t + 1500) * (t + 1500);
    141
    142			off2 += 7 * tmp;
    143			sens2 += (11 * tmp) >> 1;
    144		}
    145
    146		t -= t2;
    147		off -= off2;
    148		sens -= sens2;
    149	}
    150
    151	*temp = t;
    152	*pressure = (((p * sens) >> 21) - off) >> 15;
    153
    154	return 0;
    155}
    156
    157static int ms5607_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
    158					       s32 *temp, s32 *pressure)
    159{
    160	s32 t = *temp, p = *pressure;
    161	s64 off, sens, dt;
    162
    163	dt = t - (chip_info->prom[5] << 8);
    164	off = ((s64)chip_info->prom[2] << 17) + ((chip_info->prom[4] * dt) >> 6);
    165	sens = ((s64)chip_info->prom[1] << 16) + ((chip_info->prom[3] * dt) >> 7);
    166
    167	t = 2000 + ((chip_info->prom[6] * dt) >> 23);
    168	if (t < 2000) {
    169		s64 off2, sens2, t2, tmp;
    170
    171		t2 = (dt * dt) >> 31;
    172		tmp = (t - 2000) * (t - 2000);
    173		off2 = (61 * tmp) >> 4;
    174		sens2 = tmp << 1;
    175
    176		if (t < -1500) {
    177			tmp = (t + 1500) * (t + 1500);
    178			off2 += 15 * tmp;
    179			sens2 += 8 * tmp;
    180		}
    181
    182		t -= t2;
    183		off -= off2;
    184		sens -= sens2;
    185	}
    186
    187	*temp = t;
    188	*pressure = (((p * sens) >> 21) - off) >> 15;
    189
    190	return 0;
    191}
    192
    193static int ms5611_reset(struct iio_dev *indio_dev)
    194{
    195	int ret;
    196	struct ms5611_state *st = iio_priv(indio_dev);
    197
    198	ret = st->reset(st);
    199	if (ret < 0) {
    200		dev_err(&indio_dev->dev, "failed to reset device\n");
    201		return ret;
    202	}
    203
    204	usleep_range(3000, 4000);
    205
    206	return 0;
    207}
    208
    209static irqreturn_t ms5611_trigger_handler(int irq, void *p)
    210{
    211	struct iio_poll_func *pf = p;
    212	struct iio_dev *indio_dev = pf->indio_dev;
    213	struct ms5611_state *st = iio_priv(indio_dev);
    214	/* Ensure buffer elements are naturally aligned */
    215	struct {
    216		s32 channels[2];
    217		s64 ts __aligned(8);
    218	} scan;
    219	int ret;
    220
    221	mutex_lock(&st->lock);
    222	ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1],
    223					    &scan.channels[0]);
    224	mutex_unlock(&st->lock);
    225	if (ret < 0)
    226		goto err;
    227
    228	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
    229					   iio_get_time_ns(indio_dev));
    230
    231err:
    232	iio_trigger_notify_done(indio_dev->trig);
    233
    234	return IRQ_HANDLED;
    235}
    236
    237static int ms5611_read_raw(struct iio_dev *indio_dev,
    238			   struct iio_chan_spec const *chan,
    239			   int *val, int *val2, long mask)
    240{
    241	int ret;
    242	s32 temp, pressure;
    243	struct ms5611_state *st = iio_priv(indio_dev);
    244
    245	switch (mask) {
    246	case IIO_CHAN_INFO_PROCESSED:
    247		mutex_lock(&st->lock);
    248		ret = ms5611_read_temp_and_pressure(indio_dev,
    249						    &temp, &pressure);
    250		mutex_unlock(&st->lock);
    251		if (ret < 0)
    252			return ret;
    253
    254		switch (chan->type) {
    255		case IIO_TEMP:
    256			*val = temp * 10;
    257			return IIO_VAL_INT;
    258		case IIO_PRESSURE:
    259			*val = pressure / 1000;
    260			*val2 = (pressure % 1000) * 1000;
    261			return IIO_VAL_INT_PLUS_MICRO;
    262		default:
    263			return -EINVAL;
    264		}
    265	case IIO_CHAN_INFO_SCALE:
    266		switch (chan->type) {
    267		case IIO_TEMP:
    268			*val = 10;
    269			return IIO_VAL_INT;
    270		case IIO_PRESSURE:
    271			*val = 0;
    272			*val2 = 1000;
    273			return IIO_VAL_INT_PLUS_MICRO;
    274		default:
    275			return -EINVAL;
    276		}
    277	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
    278		if (chan->type != IIO_TEMP && chan->type != IIO_PRESSURE)
    279			break;
    280		mutex_lock(&st->lock);
    281		if (chan->type == IIO_TEMP)
    282			*val = (int)st->temp_osr->rate;
    283		else
    284			*val = (int)st->pressure_osr->rate;
    285		mutex_unlock(&st->lock);
    286		return IIO_VAL_INT;
    287	}
    288
    289	return -EINVAL;
    290}
    291
    292static const struct ms5611_osr *ms5611_find_osr(int rate,
    293						const struct ms5611_osr *osr,
    294						size_t count)
    295{
    296	unsigned int r;
    297
    298	for (r = 0; r < count; r++)
    299		if ((unsigned short)rate == osr[r].rate)
    300			break;
    301	if (r >= count)
    302		return NULL;
    303	return &osr[r];
    304}
    305
    306static int ms5611_write_raw(struct iio_dev *indio_dev,
    307			    struct iio_chan_spec const *chan,
    308			    int val, int val2, long mask)
    309{
    310	struct ms5611_state *st = iio_priv(indio_dev);
    311	const struct ms5611_osr *osr = NULL;
    312	int ret;
    313
    314	if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
    315		return -EINVAL;
    316
    317	if (chan->type == IIO_TEMP)
    318		osr = ms5611_find_osr(val, ms5611_avail_temp_osr,
    319				      ARRAY_SIZE(ms5611_avail_temp_osr));
    320	else if (chan->type == IIO_PRESSURE)
    321		osr = ms5611_find_osr(val, ms5611_avail_pressure_osr,
    322				      ARRAY_SIZE(ms5611_avail_pressure_osr));
    323	if (!osr)
    324		return -EINVAL;
    325
    326	ret = iio_device_claim_direct_mode(indio_dev);
    327	if (ret)
    328		return ret;
    329
    330	mutex_lock(&st->lock);
    331
    332	if (chan->type == IIO_TEMP)
    333		st->temp_osr = osr;
    334	else
    335		st->pressure_osr = osr;
    336
    337	mutex_unlock(&st->lock);
    338	iio_device_release_direct_mode(indio_dev);
    339
    340	return 0;
    341}
    342
    343static const unsigned long ms5611_scan_masks[] = {0x3, 0};
    344
    345static struct ms5611_chip_info chip_info_tbl[] = {
    346	[MS5611] = {
    347		.temp_and_pressure_compensate = ms5611_temp_and_pressure_compensate,
    348	},
    349	[MS5607] = {
    350		.temp_and_pressure_compensate = ms5607_temp_and_pressure_compensate,
    351	}
    352};
    353
    354static const struct iio_chan_spec ms5611_channels[] = {
    355	{
    356		.type = IIO_PRESSURE,
    357		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
    358			BIT(IIO_CHAN_INFO_SCALE) |
    359			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
    360		.scan_index = 0,
    361		.scan_type = {
    362			.sign = 's',
    363			.realbits = 32,
    364			.storagebits = 32,
    365			.endianness = IIO_CPU,
    366		},
    367	},
    368	{
    369		.type = IIO_TEMP,
    370		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
    371			BIT(IIO_CHAN_INFO_SCALE) |
    372			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
    373		.scan_index = 1,
    374		.scan_type = {
    375			.sign = 's',
    376			.realbits = 32,
    377			.storagebits = 32,
    378			.endianness = IIO_CPU,
    379		},
    380	},
    381	IIO_CHAN_SOFT_TIMESTAMP(2),
    382};
    383
    384static const struct iio_info ms5611_info = {
    385	.read_raw = &ms5611_read_raw,
    386	.write_raw = &ms5611_write_raw,
    387	.attrs = &ms5611_attribute_group,
    388};
    389
    390static int ms5611_init(struct iio_dev *indio_dev)
    391{
    392	int ret;
    393	struct ms5611_state *st = iio_priv(indio_dev);
    394
    395	/* Enable attached regulator if any. */
    396	st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
    397	if (IS_ERR(st->vdd))
    398		return PTR_ERR(st->vdd);
    399
    400	ret = regulator_enable(st->vdd);
    401	if (ret) {
    402		dev_err(indio_dev->dev.parent,
    403			"failed to enable Vdd supply: %d\n", ret);
    404		return ret;
    405	}
    406
    407	ret = ms5611_reset(indio_dev);
    408	if (ret < 0)
    409		goto err_regulator_disable;
    410
    411	ret = ms5611_read_prom(indio_dev);
    412	if (ret < 0)
    413		goto err_regulator_disable;
    414
    415	return 0;
    416
    417err_regulator_disable:
    418	regulator_disable(st->vdd);
    419	return ret;
    420}
    421
    422static void ms5611_fini(const struct iio_dev *indio_dev)
    423{
    424	const struct ms5611_state *st = iio_priv(indio_dev);
    425
    426	regulator_disable(st->vdd);
    427}
    428
    429int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
    430		 const char *name, int type)
    431{
    432	int ret;
    433	struct ms5611_state *st = iio_priv(indio_dev);
    434
    435	mutex_init(&st->lock);
    436	st->chip_info = &chip_info_tbl[type];
    437	st->temp_osr =
    438		&ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1];
    439	st->pressure_osr =
    440		&ms5611_avail_pressure_osr[ARRAY_SIZE(ms5611_avail_pressure_osr)
    441					   - 1];
    442	indio_dev->name = name;
    443	indio_dev->info = &ms5611_info;
    444	indio_dev->channels = ms5611_channels;
    445	indio_dev->num_channels = ARRAY_SIZE(ms5611_channels);
    446	indio_dev->modes = INDIO_DIRECT_MODE;
    447	indio_dev->available_scan_masks = ms5611_scan_masks;
    448
    449	ret = ms5611_init(indio_dev);
    450	if (ret < 0)
    451		return ret;
    452
    453	ret = iio_triggered_buffer_setup(indio_dev, NULL,
    454					 ms5611_trigger_handler, NULL);
    455	if (ret < 0) {
    456		dev_err(dev, "iio triggered buffer setup failed\n");
    457		goto err_fini;
    458	}
    459
    460	ret = iio_device_register(indio_dev);
    461	if (ret < 0) {
    462		dev_err(dev, "unable to register iio device\n");
    463		goto err_buffer_cleanup;
    464	}
    465
    466	return 0;
    467
    468err_buffer_cleanup:
    469	iio_triggered_buffer_cleanup(indio_dev);
    470err_fini:
    471	ms5611_fini(indio_dev);
    472	return ret;
    473}
    474EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611);
    475
    476void ms5611_remove(struct iio_dev *indio_dev)
    477{
    478	iio_device_unregister(indio_dev);
    479	iio_triggered_buffer_cleanup(indio_dev);
    480	ms5611_fini(indio_dev);
    481}
    482EXPORT_SYMBOL_NS(ms5611_remove, IIO_MS5611);
    483
    484MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
    485MODULE_DESCRIPTION("MS5611 core driver");
    486MODULE_LICENSE("GPL v2");