162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2011 Jonathan Cameron
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * A reference industrial I/O driver to illustrate the functionality available.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * There are numerous real drivers to illustrate the finer points.
862306a36Sopenharmony_ci * The purpose of this driver is to provide a driver with far more comments
962306a36Sopenharmony_ci * and explanatory notes than any 'real' driver would have.
1062306a36Sopenharmony_ci * Anyone starting out writing an IIO driver should first make sure they
1162306a36Sopenharmony_ci * understand all of this driver except those bits specifically marked
1262306a36Sopenharmony_ci * as being present to allow us to 'fake' the presence of hardware.
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/string.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/iio/iio.h>
2062306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2162306a36Sopenharmony_ci#include <linux/iio/events.h>
2262306a36Sopenharmony_ci#include <linux/iio/buffer.h>
2362306a36Sopenharmony_ci#include <linux/iio/sw_device.h>
2462306a36Sopenharmony_ci#include "iio_simple_dummy.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic const struct config_item_type iio_dummy_type = {
2762306a36Sopenharmony_ci	.ct_owner = THIS_MODULE,
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/**
3162306a36Sopenharmony_ci * struct iio_dummy_accel_calibscale - realworld to register mapping
3262306a36Sopenharmony_ci * @val: first value in read_raw - here integer part.
3362306a36Sopenharmony_ci * @val2: second value in read_raw etc - here micro part.
3462306a36Sopenharmony_ci * @regval: register value - magic device specific numbers.
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_cistruct iio_dummy_accel_calibscale {
3762306a36Sopenharmony_ci	int val;
3862306a36Sopenharmony_ci	int val2;
3962306a36Sopenharmony_ci	int regval; /* what would be written to hardware */
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const struct iio_dummy_accel_calibscale dummy_scales[] = {
4362306a36Sopenharmony_ci	{ 0, 100, 0x8 }, /* 0.000100 */
4462306a36Sopenharmony_ci	{ 0, 133, 0x7 }, /* 0.000133 */
4562306a36Sopenharmony_ci	{ 733, 13, 0x9 }, /* 733.000013 */
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/*
5162306a36Sopenharmony_ci * simple event - triggered when value rises above
5262306a36Sopenharmony_ci * a threshold
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_cistatic const struct iio_event_spec iio_dummy_event = {
5562306a36Sopenharmony_ci	.type = IIO_EV_TYPE_THRESH,
5662306a36Sopenharmony_ci	.dir = IIO_EV_DIR_RISING,
5762306a36Sopenharmony_ci	.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/*
6162306a36Sopenharmony_ci * simple step detect event - triggered when a step is detected
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistatic const struct iio_event_spec step_detect_event = {
6462306a36Sopenharmony_ci	.type = IIO_EV_TYPE_CHANGE,
6562306a36Sopenharmony_ci	.dir = IIO_EV_DIR_NONE,
6662306a36Sopenharmony_ci	.mask_separate = BIT(IIO_EV_INFO_ENABLE),
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/*
7062306a36Sopenharmony_ci * simple transition event - triggered when the reported running confidence
7162306a36Sopenharmony_ci * value rises above a threshold value
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_cistatic const struct iio_event_spec iio_running_event = {
7462306a36Sopenharmony_ci	.type = IIO_EV_TYPE_THRESH,
7562306a36Sopenharmony_ci	.dir = IIO_EV_DIR_RISING,
7662306a36Sopenharmony_ci	.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * simple transition event - triggered when the reported walking confidence
8162306a36Sopenharmony_ci * value falls under a threshold value
8262306a36Sopenharmony_ci */
8362306a36Sopenharmony_cistatic const struct iio_event_spec iio_walking_event = {
8462306a36Sopenharmony_ci	.type = IIO_EV_TYPE_THRESH,
8562306a36Sopenharmony_ci	.dir = IIO_EV_DIR_FALLING,
8662306a36Sopenharmony_ci	.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci#endif
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/*
9162306a36Sopenharmony_ci * iio_dummy_channels - Description of available channels
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * This array of structures tells the IIO core about what the device
9462306a36Sopenharmony_ci * actually provides for a given channel.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistatic const struct iio_chan_spec iio_dummy_channels[] = {
9762306a36Sopenharmony_ci	/* indexed ADC channel in_voltage0_raw etc */
9862306a36Sopenharmony_ci	{
9962306a36Sopenharmony_ci		.type = IIO_VOLTAGE,
10062306a36Sopenharmony_ci		/* Channel has a numeric index of 0 */
10162306a36Sopenharmony_ci		.indexed = 1,
10262306a36Sopenharmony_ci		.channel = 0,
10362306a36Sopenharmony_ci		/* What other information is available? */
10462306a36Sopenharmony_ci		.info_mask_separate =
10562306a36Sopenharmony_ci		/*
10662306a36Sopenharmony_ci		 * in_voltage0_raw
10762306a36Sopenharmony_ci		 * Raw (unscaled no bias removal etc) measurement
10862306a36Sopenharmony_ci		 * from the device.
10962306a36Sopenharmony_ci		 */
11062306a36Sopenharmony_ci		BIT(IIO_CHAN_INFO_RAW) |
11162306a36Sopenharmony_ci		/*
11262306a36Sopenharmony_ci		 * in_voltage0_offset
11362306a36Sopenharmony_ci		 * Offset for userspace to apply prior to scale
11462306a36Sopenharmony_ci		 * when converting to standard units (microvolts)
11562306a36Sopenharmony_ci		 */
11662306a36Sopenharmony_ci		BIT(IIO_CHAN_INFO_OFFSET) |
11762306a36Sopenharmony_ci		/*
11862306a36Sopenharmony_ci		 * in_voltage0_scale
11962306a36Sopenharmony_ci		 * Multipler for userspace to apply post offset
12062306a36Sopenharmony_ci		 * when converting to standard units (microvolts)
12162306a36Sopenharmony_ci		 */
12262306a36Sopenharmony_ci		BIT(IIO_CHAN_INFO_SCALE),
12362306a36Sopenharmony_ci		/*
12462306a36Sopenharmony_ci		 * sampling_frequency
12562306a36Sopenharmony_ci		 * The frequency in Hz at which the channels are sampled
12662306a36Sopenharmony_ci		 */
12762306a36Sopenharmony_ci		.info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ),
12862306a36Sopenharmony_ci		/* The ordering of elements in the buffer via an enum */
12962306a36Sopenharmony_ci		.scan_index = DUMMY_INDEX_VOLTAGE_0,
13062306a36Sopenharmony_ci		.scan_type = { /* Description of storage in buffer */
13162306a36Sopenharmony_ci			.sign = 'u', /* unsigned */
13262306a36Sopenharmony_ci			.realbits = 13, /* 13 bits */
13362306a36Sopenharmony_ci			.storagebits = 16, /* 16 bits used for storage */
13462306a36Sopenharmony_ci			.shift = 0, /* zero shift */
13562306a36Sopenharmony_ci		},
13662306a36Sopenharmony_ci#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
13762306a36Sopenharmony_ci		.event_spec = &iio_dummy_event,
13862306a36Sopenharmony_ci		.num_event_specs = 1,
13962306a36Sopenharmony_ci#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
14062306a36Sopenharmony_ci	},
14162306a36Sopenharmony_ci	/* Differential ADC channel in_voltage1-voltage2_raw etc*/
14262306a36Sopenharmony_ci	{
14362306a36Sopenharmony_ci		.type = IIO_VOLTAGE,
14462306a36Sopenharmony_ci		.differential = 1,
14562306a36Sopenharmony_ci		/*
14662306a36Sopenharmony_ci		 * Indexing for differential channels uses channel
14762306a36Sopenharmony_ci		 * for the positive part, channel2 for the negative.
14862306a36Sopenharmony_ci		 */
14962306a36Sopenharmony_ci		.indexed = 1,
15062306a36Sopenharmony_ci		.channel = 1,
15162306a36Sopenharmony_ci		.channel2 = 2,
15262306a36Sopenharmony_ci		/*
15362306a36Sopenharmony_ci		 * in_voltage1-voltage2_raw
15462306a36Sopenharmony_ci		 * Raw (unscaled no bias removal etc) measurement
15562306a36Sopenharmony_ci		 * from the device.
15662306a36Sopenharmony_ci		 */
15762306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
15862306a36Sopenharmony_ci		/*
15962306a36Sopenharmony_ci		 * in_voltage-voltage_scale
16062306a36Sopenharmony_ci		 * Shared version of scale - shared by differential
16162306a36Sopenharmony_ci		 * input channels of type IIO_VOLTAGE.
16262306a36Sopenharmony_ci		 */
16362306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
16462306a36Sopenharmony_ci		/*
16562306a36Sopenharmony_ci		 * sampling_frequency
16662306a36Sopenharmony_ci		 * The frequency in Hz at which the channels are sampled
16762306a36Sopenharmony_ci		 */
16862306a36Sopenharmony_ci		.scan_index = DUMMY_INDEX_DIFFVOLTAGE_1M2,
16962306a36Sopenharmony_ci		.scan_type = { /* Description of storage in buffer */
17062306a36Sopenharmony_ci			.sign = 's', /* signed */
17162306a36Sopenharmony_ci			.realbits = 12, /* 12 bits */
17262306a36Sopenharmony_ci			.storagebits = 16, /* 16 bits used for storage */
17362306a36Sopenharmony_ci			.shift = 0, /* zero shift */
17462306a36Sopenharmony_ci		},
17562306a36Sopenharmony_ci	},
17662306a36Sopenharmony_ci	/* Differential ADC channel in_voltage3-voltage4_raw etc*/
17762306a36Sopenharmony_ci	{
17862306a36Sopenharmony_ci		.type = IIO_VOLTAGE,
17962306a36Sopenharmony_ci		.differential = 1,
18062306a36Sopenharmony_ci		.indexed = 1,
18162306a36Sopenharmony_ci		.channel = 3,
18262306a36Sopenharmony_ci		.channel2 = 4,
18362306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
18462306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
18562306a36Sopenharmony_ci		.info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ),
18662306a36Sopenharmony_ci		.scan_index = DUMMY_INDEX_DIFFVOLTAGE_3M4,
18762306a36Sopenharmony_ci		.scan_type = {
18862306a36Sopenharmony_ci			.sign = 's',
18962306a36Sopenharmony_ci			.realbits = 11,
19062306a36Sopenharmony_ci			.storagebits = 16,
19162306a36Sopenharmony_ci			.shift = 0,
19262306a36Sopenharmony_ci		},
19362306a36Sopenharmony_ci	},
19462306a36Sopenharmony_ci	/*
19562306a36Sopenharmony_ci	 * 'modified' (i.e. axis specified) acceleration channel
19662306a36Sopenharmony_ci	 * in_accel_z_raw
19762306a36Sopenharmony_ci	 */
19862306a36Sopenharmony_ci	{
19962306a36Sopenharmony_ci		.type = IIO_ACCEL,
20062306a36Sopenharmony_ci		.modified = 1,
20162306a36Sopenharmony_ci		/* Channel 2 is use for modifiers */
20262306a36Sopenharmony_ci		.channel2 = IIO_MOD_X,
20362306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
20462306a36Sopenharmony_ci		/*
20562306a36Sopenharmony_ci		 * Internal bias and gain correction values. Applied
20662306a36Sopenharmony_ci		 * by the hardware or driver prior to userspace
20762306a36Sopenharmony_ci		 * seeing the readings. Typically part of hardware
20862306a36Sopenharmony_ci		 * calibration.
20962306a36Sopenharmony_ci		 */
21062306a36Sopenharmony_ci		BIT(IIO_CHAN_INFO_CALIBSCALE) |
21162306a36Sopenharmony_ci		BIT(IIO_CHAN_INFO_CALIBBIAS),
21262306a36Sopenharmony_ci		.info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ),
21362306a36Sopenharmony_ci		.scan_index = DUMMY_INDEX_ACCELX,
21462306a36Sopenharmony_ci		.scan_type = { /* Description of storage in buffer */
21562306a36Sopenharmony_ci			.sign = 's', /* signed */
21662306a36Sopenharmony_ci			.realbits = 16, /* 16 bits */
21762306a36Sopenharmony_ci			.storagebits = 16, /* 16 bits used for storage */
21862306a36Sopenharmony_ci			.shift = 0, /* zero shift */
21962306a36Sopenharmony_ci		},
22062306a36Sopenharmony_ci	},
22162306a36Sopenharmony_ci	/*
22262306a36Sopenharmony_ci	 * Convenience macro for timestamps. 4 is the index in
22362306a36Sopenharmony_ci	 * the buffer.
22462306a36Sopenharmony_ci	 */
22562306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(4),
22662306a36Sopenharmony_ci	/* DAC channel out_voltage0_raw */
22762306a36Sopenharmony_ci	{
22862306a36Sopenharmony_ci		.type = IIO_VOLTAGE,
22962306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
23062306a36Sopenharmony_ci		.scan_index = -1, /* No buffer support */
23162306a36Sopenharmony_ci		.output = 1,
23262306a36Sopenharmony_ci		.indexed = 1,
23362306a36Sopenharmony_ci		.channel = 0,
23462306a36Sopenharmony_ci	},
23562306a36Sopenharmony_ci	{
23662306a36Sopenharmony_ci		.type = IIO_STEPS,
23762306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_ENABLE) |
23862306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_CALIBHEIGHT),
23962306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
24062306a36Sopenharmony_ci		.scan_index = -1, /* No buffer support */
24162306a36Sopenharmony_ci#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
24262306a36Sopenharmony_ci		.event_spec = &step_detect_event,
24362306a36Sopenharmony_ci		.num_event_specs = 1,
24462306a36Sopenharmony_ci#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
24562306a36Sopenharmony_ci	},
24662306a36Sopenharmony_ci	{
24762306a36Sopenharmony_ci		.type = IIO_ACTIVITY,
24862306a36Sopenharmony_ci		.modified = 1,
24962306a36Sopenharmony_ci		.channel2 = IIO_MOD_RUNNING,
25062306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
25162306a36Sopenharmony_ci		.scan_index = -1, /* No buffer support */
25262306a36Sopenharmony_ci#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
25362306a36Sopenharmony_ci		.event_spec = &iio_running_event,
25462306a36Sopenharmony_ci		.num_event_specs = 1,
25562306a36Sopenharmony_ci#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
25662306a36Sopenharmony_ci	},
25762306a36Sopenharmony_ci	{
25862306a36Sopenharmony_ci		.type = IIO_ACTIVITY,
25962306a36Sopenharmony_ci		.modified = 1,
26062306a36Sopenharmony_ci		.channel2 = IIO_MOD_WALKING,
26162306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
26262306a36Sopenharmony_ci		.scan_index = -1, /* No buffer support */
26362306a36Sopenharmony_ci#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
26462306a36Sopenharmony_ci		.event_spec = &iio_walking_event,
26562306a36Sopenharmony_ci		.num_event_specs = 1,
26662306a36Sopenharmony_ci#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
26762306a36Sopenharmony_ci	},
26862306a36Sopenharmony_ci};
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/**
27162306a36Sopenharmony_ci * iio_dummy_read_raw() - data read function.
27262306a36Sopenharmony_ci * @indio_dev:	the struct iio_dev associated with this device instance
27362306a36Sopenharmony_ci * @chan:	the channel whose data is to be read
27462306a36Sopenharmony_ci * @val:	first element of returned value (typically INT)
27562306a36Sopenharmony_ci * @val2:	second element of returned value (typically MICRO)
27662306a36Sopenharmony_ci * @mask:	what we actually want to read as per the info_mask_*
27762306a36Sopenharmony_ci *		in iio_chan_spec.
27862306a36Sopenharmony_ci */
27962306a36Sopenharmony_cistatic int iio_dummy_read_raw(struct iio_dev *indio_dev,
28062306a36Sopenharmony_ci			      struct iio_chan_spec const *chan,
28162306a36Sopenharmony_ci			      int *val,
28262306a36Sopenharmony_ci			      int *val2,
28362306a36Sopenharmony_ci			      long mask)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct iio_dummy_state *st = iio_priv(indio_dev);
28662306a36Sopenharmony_ci	int ret = -EINVAL;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	mutex_lock(&st->lock);
28962306a36Sopenharmony_ci	switch (mask) {
29062306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW: /* magic value - channel value read */
29162306a36Sopenharmony_ci		switch (chan->type) {
29262306a36Sopenharmony_ci		case IIO_VOLTAGE:
29362306a36Sopenharmony_ci			if (chan->output) {
29462306a36Sopenharmony_ci				/* Set integer part to cached value */
29562306a36Sopenharmony_ci				*val = st->dac_val;
29662306a36Sopenharmony_ci				ret = IIO_VAL_INT;
29762306a36Sopenharmony_ci			} else if (chan->differential) {
29862306a36Sopenharmony_ci				if (chan->channel == 1)
29962306a36Sopenharmony_ci					*val = st->differential_adc_val[0];
30062306a36Sopenharmony_ci				else
30162306a36Sopenharmony_ci					*val = st->differential_adc_val[1];
30262306a36Sopenharmony_ci				ret = IIO_VAL_INT;
30362306a36Sopenharmony_ci			} else {
30462306a36Sopenharmony_ci				*val = st->single_ended_adc_val;
30562306a36Sopenharmony_ci				ret = IIO_VAL_INT;
30662306a36Sopenharmony_ci			}
30762306a36Sopenharmony_ci			break;
30862306a36Sopenharmony_ci		case IIO_ACCEL:
30962306a36Sopenharmony_ci			*val = st->accel_val;
31062306a36Sopenharmony_ci			ret = IIO_VAL_INT;
31162306a36Sopenharmony_ci			break;
31262306a36Sopenharmony_ci		default:
31362306a36Sopenharmony_ci			break;
31462306a36Sopenharmony_ci		}
31562306a36Sopenharmony_ci		break;
31662306a36Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
31762306a36Sopenharmony_ci		switch (chan->type) {
31862306a36Sopenharmony_ci		case IIO_STEPS:
31962306a36Sopenharmony_ci			*val = st->steps;
32062306a36Sopenharmony_ci			ret = IIO_VAL_INT;
32162306a36Sopenharmony_ci			break;
32262306a36Sopenharmony_ci		case IIO_ACTIVITY:
32362306a36Sopenharmony_ci			switch (chan->channel2) {
32462306a36Sopenharmony_ci			case IIO_MOD_RUNNING:
32562306a36Sopenharmony_ci				*val = st->activity_running;
32662306a36Sopenharmony_ci				ret = IIO_VAL_INT;
32762306a36Sopenharmony_ci				break;
32862306a36Sopenharmony_ci			case IIO_MOD_WALKING:
32962306a36Sopenharmony_ci				*val = st->activity_walking;
33062306a36Sopenharmony_ci				ret = IIO_VAL_INT;
33162306a36Sopenharmony_ci				break;
33262306a36Sopenharmony_ci			default:
33362306a36Sopenharmony_ci				break;
33462306a36Sopenharmony_ci			}
33562306a36Sopenharmony_ci			break;
33662306a36Sopenharmony_ci		default:
33762306a36Sopenharmony_ci			break;
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci		break;
34062306a36Sopenharmony_ci	case IIO_CHAN_INFO_OFFSET:
34162306a36Sopenharmony_ci		/* only single ended adc -> 7 */
34262306a36Sopenharmony_ci		*val = 7;
34362306a36Sopenharmony_ci		ret = IIO_VAL_INT;
34462306a36Sopenharmony_ci		break;
34562306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
34662306a36Sopenharmony_ci		switch (chan->type) {
34762306a36Sopenharmony_ci		case IIO_VOLTAGE:
34862306a36Sopenharmony_ci			switch (chan->differential) {
34962306a36Sopenharmony_ci			case 0:
35062306a36Sopenharmony_ci				/* only single ended adc -> 0.001333 */
35162306a36Sopenharmony_ci				*val = 0;
35262306a36Sopenharmony_ci				*val2 = 1333;
35362306a36Sopenharmony_ci				ret = IIO_VAL_INT_PLUS_MICRO;
35462306a36Sopenharmony_ci				break;
35562306a36Sopenharmony_ci			case 1:
35662306a36Sopenharmony_ci				/* all differential adc -> 0.000001344 */
35762306a36Sopenharmony_ci				*val = 0;
35862306a36Sopenharmony_ci				*val2 = 1344;
35962306a36Sopenharmony_ci				ret = IIO_VAL_INT_PLUS_NANO;
36062306a36Sopenharmony_ci			}
36162306a36Sopenharmony_ci			break;
36262306a36Sopenharmony_ci		default:
36362306a36Sopenharmony_ci			break;
36462306a36Sopenharmony_ci		}
36562306a36Sopenharmony_ci		break;
36662306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
36762306a36Sopenharmony_ci		/* only the acceleration axis - read from cache */
36862306a36Sopenharmony_ci		*val = st->accel_calibbias;
36962306a36Sopenharmony_ci		ret = IIO_VAL_INT;
37062306a36Sopenharmony_ci		break;
37162306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBSCALE:
37262306a36Sopenharmony_ci		*val = st->accel_calibscale->val;
37362306a36Sopenharmony_ci		*val2 = st->accel_calibscale->val2;
37462306a36Sopenharmony_ci		ret = IIO_VAL_INT_PLUS_MICRO;
37562306a36Sopenharmony_ci		break;
37662306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
37762306a36Sopenharmony_ci		*val = 3;
37862306a36Sopenharmony_ci		*val2 = 33;
37962306a36Sopenharmony_ci		ret = IIO_VAL_INT_PLUS_NANO;
38062306a36Sopenharmony_ci		break;
38162306a36Sopenharmony_ci	case IIO_CHAN_INFO_ENABLE:
38262306a36Sopenharmony_ci		switch (chan->type) {
38362306a36Sopenharmony_ci		case IIO_STEPS:
38462306a36Sopenharmony_ci			*val = st->steps_enabled;
38562306a36Sopenharmony_ci			ret = IIO_VAL_INT;
38662306a36Sopenharmony_ci			break;
38762306a36Sopenharmony_ci		default:
38862306a36Sopenharmony_ci			break;
38962306a36Sopenharmony_ci		}
39062306a36Sopenharmony_ci		break;
39162306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBHEIGHT:
39262306a36Sopenharmony_ci		switch (chan->type) {
39362306a36Sopenharmony_ci		case IIO_STEPS:
39462306a36Sopenharmony_ci			*val = st->height;
39562306a36Sopenharmony_ci			ret = IIO_VAL_INT;
39662306a36Sopenharmony_ci			break;
39762306a36Sopenharmony_ci		default:
39862306a36Sopenharmony_ci			break;
39962306a36Sopenharmony_ci		}
40062306a36Sopenharmony_ci		break;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	default:
40362306a36Sopenharmony_ci		break;
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci	mutex_unlock(&st->lock);
40662306a36Sopenharmony_ci	return ret;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci/**
41062306a36Sopenharmony_ci * iio_dummy_write_raw() - data write function.
41162306a36Sopenharmony_ci * @indio_dev:	the struct iio_dev associated with this device instance
41262306a36Sopenharmony_ci * @chan:	the channel whose data is to be written
41362306a36Sopenharmony_ci * @val:	first element of value to set (typically INT)
41462306a36Sopenharmony_ci * @val2:	second element of value to set (typically MICRO)
41562306a36Sopenharmony_ci * @mask:	what we actually want to write as per the info_mask_*
41662306a36Sopenharmony_ci *		in iio_chan_spec.
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci * Note that all raw writes are assumed IIO_VAL_INT and info mask elements
41962306a36Sopenharmony_ci * are assumed to be IIO_INT_PLUS_MICRO unless the callback write_raw_get_fmt
42062306a36Sopenharmony_ci * in struct iio_info is provided by the driver.
42162306a36Sopenharmony_ci */
42262306a36Sopenharmony_cistatic int iio_dummy_write_raw(struct iio_dev *indio_dev,
42362306a36Sopenharmony_ci			       struct iio_chan_spec const *chan,
42462306a36Sopenharmony_ci			       int val,
42562306a36Sopenharmony_ci			       int val2,
42662306a36Sopenharmony_ci			       long mask)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	int i;
42962306a36Sopenharmony_ci	int ret = 0;
43062306a36Sopenharmony_ci	struct iio_dummy_state *st = iio_priv(indio_dev);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	switch (mask) {
43362306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
43462306a36Sopenharmony_ci		switch (chan->type) {
43562306a36Sopenharmony_ci		case IIO_VOLTAGE:
43662306a36Sopenharmony_ci			if (chan->output == 0)
43762306a36Sopenharmony_ci				return -EINVAL;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci			/* Locking not required as writing single value */
44062306a36Sopenharmony_ci			mutex_lock(&st->lock);
44162306a36Sopenharmony_ci			st->dac_val = val;
44262306a36Sopenharmony_ci			mutex_unlock(&st->lock);
44362306a36Sopenharmony_ci			return 0;
44462306a36Sopenharmony_ci		default:
44562306a36Sopenharmony_ci			return -EINVAL;
44662306a36Sopenharmony_ci		}
44762306a36Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
44862306a36Sopenharmony_ci		switch (chan->type) {
44962306a36Sopenharmony_ci		case IIO_STEPS:
45062306a36Sopenharmony_ci			mutex_lock(&st->lock);
45162306a36Sopenharmony_ci			st->steps = val;
45262306a36Sopenharmony_ci			mutex_unlock(&st->lock);
45362306a36Sopenharmony_ci			return 0;
45462306a36Sopenharmony_ci		case IIO_ACTIVITY:
45562306a36Sopenharmony_ci			if (val < 0)
45662306a36Sopenharmony_ci				val = 0;
45762306a36Sopenharmony_ci			if (val > 100)
45862306a36Sopenharmony_ci				val = 100;
45962306a36Sopenharmony_ci			switch (chan->channel2) {
46062306a36Sopenharmony_ci			case IIO_MOD_RUNNING:
46162306a36Sopenharmony_ci				st->activity_running = val;
46262306a36Sopenharmony_ci				return 0;
46362306a36Sopenharmony_ci			case IIO_MOD_WALKING:
46462306a36Sopenharmony_ci				st->activity_walking = val;
46562306a36Sopenharmony_ci				return 0;
46662306a36Sopenharmony_ci			default:
46762306a36Sopenharmony_ci				return -EINVAL;
46862306a36Sopenharmony_ci			}
46962306a36Sopenharmony_ci			break;
47062306a36Sopenharmony_ci		default:
47162306a36Sopenharmony_ci			return -EINVAL;
47262306a36Sopenharmony_ci		}
47362306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBSCALE:
47462306a36Sopenharmony_ci		mutex_lock(&st->lock);
47562306a36Sopenharmony_ci		/* Compare against table - hard matching here */
47662306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(dummy_scales); i++)
47762306a36Sopenharmony_ci			if (val == dummy_scales[i].val &&
47862306a36Sopenharmony_ci			    val2 == dummy_scales[i].val2)
47962306a36Sopenharmony_ci				break;
48062306a36Sopenharmony_ci		if (i == ARRAY_SIZE(dummy_scales))
48162306a36Sopenharmony_ci			ret = -EINVAL;
48262306a36Sopenharmony_ci		else
48362306a36Sopenharmony_ci			st->accel_calibscale = &dummy_scales[i];
48462306a36Sopenharmony_ci		mutex_unlock(&st->lock);
48562306a36Sopenharmony_ci		return ret;
48662306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
48762306a36Sopenharmony_ci		mutex_lock(&st->lock);
48862306a36Sopenharmony_ci		st->accel_calibbias = val;
48962306a36Sopenharmony_ci		mutex_unlock(&st->lock);
49062306a36Sopenharmony_ci		return 0;
49162306a36Sopenharmony_ci	case IIO_CHAN_INFO_ENABLE:
49262306a36Sopenharmony_ci		switch (chan->type) {
49362306a36Sopenharmony_ci		case IIO_STEPS:
49462306a36Sopenharmony_ci			mutex_lock(&st->lock);
49562306a36Sopenharmony_ci			st->steps_enabled = val;
49662306a36Sopenharmony_ci			mutex_unlock(&st->lock);
49762306a36Sopenharmony_ci			return 0;
49862306a36Sopenharmony_ci		default:
49962306a36Sopenharmony_ci			return -EINVAL;
50062306a36Sopenharmony_ci		}
50162306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBHEIGHT:
50262306a36Sopenharmony_ci		switch (chan->type) {
50362306a36Sopenharmony_ci		case IIO_STEPS:
50462306a36Sopenharmony_ci			st->height = val;
50562306a36Sopenharmony_ci			return 0;
50662306a36Sopenharmony_ci		default:
50762306a36Sopenharmony_ci			return -EINVAL;
50862306a36Sopenharmony_ci		}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	default:
51162306a36Sopenharmony_ci		return -EINVAL;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci/*
51662306a36Sopenharmony_ci * Device type specific information.
51762306a36Sopenharmony_ci */
51862306a36Sopenharmony_cistatic const struct iio_info iio_dummy_info = {
51962306a36Sopenharmony_ci	.read_raw = &iio_dummy_read_raw,
52062306a36Sopenharmony_ci	.write_raw = &iio_dummy_write_raw,
52162306a36Sopenharmony_ci#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
52262306a36Sopenharmony_ci	.read_event_config = &iio_simple_dummy_read_event_config,
52362306a36Sopenharmony_ci	.write_event_config = &iio_simple_dummy_write_event_config,
52462306a36Sopenharmony_ci	.read_event_value = &iio_simple_dummy_read_event_value,
52562306a36Sopenharmony_ci	.write_event_value = &iio_simple_dummy_write_event_value,
52662306a36Sopenharmony_ci#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
52762306a36Sopenharmony_ci};
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/**
53062306a36Sopenharmony_ci * iio_dummy_init_device() - device instance specific init
53162306a36Sopenharmony_ci * @indio_dev: the iio device structure
53262306a36Sopenharmony_ci *
53362306a36Sopenharmony_ci * Most drivers have one of these to set up default values,
53462306a36Sopenharmony_ci * reset the device to known state etc.
53562306a36Sopenharmony_ci */
53662306a36Sopenharmony_cistatic int iio_dummy_init_device(struct iio_dev *indio_dev)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct iio_dummy_state *st = iio_priv(indio_dev);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	st->dac_val = 0;
54162306a36Sopenharmony_ci	st->single_ended_adc_val = 73;
54262306a36Sopenharmony_ci	st->differential_adc_val[0] = 33;
54362306a36Sopenharmony_ci	st->differential_adc_val[1] = -34;
54462306a36Sopenharmony_ci	st->accel_val = 34;
54562306a36Sopenharmony_ci	st->accel_calibbias = -7;
54662306a36Sopenharmony_ci	st->accel_calibscale = &dummy_scales[0];
54762306a36Sopenharmony_ci	st->steps = 47;
54862306a36Sopenharmony_ci	st->activity_running = 98;
54962306a36Sopenharmony_ci	st->activity_walking = 4;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	return 0;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/**
55562306a36Sopenharmony_ci * iio_dummy_probe() - device instance probe
55662306a36Sopenharmony_ci * @name: name of this instance.
55762306a36Sopenharmony_ci *
55862306a36Sopenharmony_ci * Arguments are bus type specific.
55962306a36Sopenharmony_ci * I2C: iio_dummy_probe(struct i2c_client *client,
56062306a36Sopenharmony_ci *                      const struct i2c_device_id *id)
56162306a36Sopenharmony_ci * SPI: iio_dummy_probe(struct spi_device *spi)
56262306a36Sopenharmony_ci */
56362306a36Sopenharmony_cistatic struct iio_sw_device *iio_dummy_probe(const char *name)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	int ret;
56662306a36Sopenharmony_ci	struct iio_dev *indio_dev;
56762306a36Sopenharmony_ci	struct iio_dummy_state *st;
56862306a36Sopenharmony_ci	struct iio_sw_device *swd;
56962306a36Sopenharmony_ci	struct device *parent = NULL;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/*
57262306a36Sopenharmony_ci	 * With hardware: Set the parent device.
57362306a36Sopenharmony_ci	 * parent = &spi->dev;
57462306a36Sopenharmony_ci	 * parent = &client->dev;
57562306a36Sopenharmony_ci	 */
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	swd = kzalloc(sizeof(*swd), GFP_KERNEL);
57862306a36Sopenharmony_ci	if (!swd)
57962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/*
58262306a36Sopenharmony_ci	 * Allocate an IIO device.
58362306a36Sopenharmony_ci	 *
58462306a36Sopenharmony_ci	 * This structure contains all generic state
58562306a36Sopenharmony_ci	 * information about the device instance.
58662306a36Sopenharmony_ci	 * It also has a region (accessed by iio_priv()
58762306a36Sopenharmony_ci	 * for chip specific state information.
58862306a36Sopenharmony_ci	 */
58962306a36Sopenharmony_ci	indio_dev = iio_device_alloc(parent, sizeof(*st));
59062306a36Sopenharmony_ci	if (!indio_dev) {
59162306a36Sopenharmony_ci		ret = -ENOMEM;
59262306a36Sopenharmony_ci		goto error_free_swd;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	st = iio_priv(indio_dev);
59662306a36Sopenharmony_ci	mutex_init(&st->lock);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	iio_dummy_init_device(indio_dev);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	 /*
60162306a36Sopenharmony_ci	 * Make the iio_dev struct available to remove function.
60262306a36Sopenharmony_ci	 * Bus equivalents
60362306a36Sopenharmony_ci	 * i2c_set_clientdata(client, indio_dev);
60462306a36Sopenharmony_ci	 * spi_set_drvdata(spi, indio_dev);
60562306a36Sopenharmony_ci	 */
60662306a36Sopenharmony_ci	swd->device = indio_dev;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/*
60962306a36Sopenharmony_ci	 * Set the device name.
61062306a36Sopenharmony_ci	 *
61162306a36Sopenharmony_ci	 * This is typically a part number and obtained from the module
61262306a36Sopenharmony_ci	 * id table.
61362306a36Sopenharmony_ci	 * e.g. for i2c and spi:
61462306a36Sopenharmony_ci	 *    indio_dev->name = id->name;
61562306a36Sopenharmony_ci	 *    indio_dev->name = spi_get_device_id(spi)->name;
61662306a36Sopenharmony_ci	 */
61762306a36Sopenharmony_ci	indio_dev->name = kstrdup(name, GFP_KERNEL);
61862306a36Sopenharmony_ci	if (!indio_dev->name) {
61962306a36Sopenharmony_ci		ret = -ENOMEM;
62062306a36Sopenharmony_ci		goto error_free_device;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/* Provide description of available channels */
62462306a36Sopenharmony_ci	indio_dev->channels = iio_dummy_channels;
62562306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(iio_dummy_channels);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/*
62862306a36Sopenharmony_ci	 * Provide device type specific interface functions and
62962306a36Sopenharmony_ci	 * constant data.
63062306a36Sopenharmony_ci	 */
63162306a36Sopenharmony_ci	indio_dev->info = &iio_dummy_info;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	/* Specify that device provides sysfs type interfaces */
63462306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	ret = iio_simple_dummy_events_register(indio_dev);
63762306a36Sopenharmony_ci	if (ret < 0)
63862306a36Sopenharmony_ci		goto error_free_name;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	ret = iio_simple_dummy_configure_buffer(indio_dev);
64162306a36Sopenharmony_ci	if (ret < 0)
64262306a36Sopenharmony_ci		goto error_unregister_events;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	ret = iio_device_register(indio_dev);
64562306a36Sopenharmony_ci	if (ret < 0)
64662306a36Sopenharmony_ci		goto error_unconfigure_buffer;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	iio_swd_group_init_type_name(swd, name, &iio_dummy_type);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	return swd;
65162306a36Sopenharmony_cierror_unconfigure_buffer:
65262306a36Sopenharmony_ci	iio_simple_dummy_unconfigure_buffer(indio_dev);
65362306a36Sopenharmony_cierror_unregister_events:
65462306a36Sopenharmony_ci	iio_simple_dummy_events_unregister(indio_dev);
65562306a36Sopenharmony_cierror_free_name:
65662306a36Sopenharmony_ci	kfree(indio_dev->name);
65762306a36Sopenharmony_cierror_free_device:
65862306a36Sopenharmony_ci	iio_device_free(indio_dev);
65962306a36Sopenharmony_cierror_free_swd:
66062306a36Sopenharmony_ci	kfree(swd);
66162306a36Sopenharmony_ci	return ERR_PTR(ret);
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/**
66562306a36Sopenharmony_ci * iio_dummy_remove() - device instance removal function
66662306a36Sopenharmony_ci * @swd: pointer to software IIO device abstraction
66762306a36Sopenharmony_ci *
66862306a36Sopenharmony_ci * Parameters follow those of iio_dummy_probe for buses.
66962306a36Sopenharmony_ci */
67062306a36Sopenharmony_cistatic int iio_dummy_remove(struct iio_sw_device *swd)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	/*
67362306a36Sopenharmony_ci	 * Get a pointer to the device instance iio_dev structure
67462306a36Sopenharmony_ci	 * from the bus subsystem. E.g.
67562306a36Sopenharmony_ci	 * struct iio_dev *indio_dev = i2c_get_clientdata(client);
67662306a36Sopenharmony_ci	 * struct iio_dev *indio_dev = spi_get_drvdata(spi);
67762306a36Sopenharmony_ci	 */
67862306a36Sopenharmony_ci	struct iio_dev *indio_dev = swd->device;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/* Unregister the device */
68162306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	/* Device specific code to power down etc */
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	/* Buffered capture related cleanup */
68662306a36Sopenharmony_ci	iio_simple_dummy_unconfigure_buffer(indio_dev);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	iio_simple_dummy_events_unregister(indio_dev);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/* Free all structures */
69162306a36Sopenharmony_ci	kfree(indio_dev->name);
69262306a36Sopenharmony_ci	iio_device_free(indio_dev);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return 0;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci/*
69862306a36Sopenharmony_ci * module_iio_sw_device_driver() -  device driver registration
69962306a36Sopenharmony_ci *
70062306a36Sopenharmony_ci * Varies depending on bus type of the device. As there is no device
70162306a36Sopenharmony_ci * here, call probe directly. For information on device registration
70262306a36Sopenharmony_ci * i2c:
70362306a36Sopenharmony_ci * Documentation/i2c/writing-clients.rst
70462306a36Sopenharmony_ci * spi:
70562306a36Sopenharmony_ci * Documentation/spi/spi-summary.rst
70662306a36Sopenharmony_ci */
70762306a36Sopenharmony_cistatic const struct iio_sw_device_ops iio_dummy_device_ops = {
70862306a36Sopenharmony_ci	.probe = iio_dummy_probe,
70962306a36Sopenharmony_ci	.remove = iio_dummy_remove,
71062306a36Sopenharmony_ci};
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic struct iio_sw_device_type iio_dummy_device = {
71362306a36Sopenharmony_ci	.name = "dummy",
71462306a36Sopenharmony_ci	.owner = THIS_MODULE,
71562306a36Sopenharmony_ci	.ops = &iio_dummy_device_ops,
71662306a36Sopenharmony_ci};
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cimodule_iio_sw_device_driver(iio_dummy_device);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ciMODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
72162306a36Sopenharmony_ciMODULE_DESCRIPTION("IIO dummy driver");
72262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
723