summaryrefslogtreecommitdiffstats
path: root/kernel/include/linux/iio/adc/ad_sigma_delta.h
blob: e7fdec4db9dac5dc9b73ccf64f3fbbd1a00c12d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * Support code for Analog Devices Sigma-Delta ADCs
 *
 * Copyright 2012 Analog Devices Inc.
 *  Author: Lars-Peter Clausen <lars@metafoo.de>
 *
 * Licensed under the GPL-2.
 */
#ifndef __AD_SIGMA_DELTA_H__
#define __AD_SIGMA_DELTA_H__

enum ad_sigma_delta_mode {
	AD_SD_MODE_CONTINUOUS = 0,
	AD_SD_MODE_SINGLE = 1,
	AD_SD_MODE_IDLE = 2,
	AD_SD_MODE_POWERDOWN = 3,
};

/**
 * struct ad_sigma_delta_calib_data - Calibration data for Sigma Delta devices
 * @mode: Calibration mode.
 * @channel: Calibration channel.
 */
struct ad_sd_calib_data {
	unsigned int mode;
	unsigned int channel;
};

struct ad_sigma_delta;
struct iio_dev;

/**
 * struct ad_sigma_delta_info - Sigma Delta driver specific callbacks and options
 * @set_channel: Will be called to select the current channel, may be NULL.
 * @set_mode: Will be called to select the current mode, may be NULL.
 * @postprocess_sample: Is called for each sampled data word, can be used to
 *		modify or drop the sample data, it, may be NULL.
 * @has_registers: true if the device has writable and readable registers, false
 *		if there is just one read-only sample data shift register.
 * @addr_shift: Shift of the register address in the communications register.
 * @read_mask: Mask for the communications register having the read bit set.
 */
struct ad_sigma_delta_info {
	int (*set_channel)(struct ad_sigma_delta *, unsigned int channel);
	int (*set_mode)(struct ad_sigma_delta *, enum ad_sigma_delta_mode mode);
	int (*postprocess_sample)(struct ad_sigma_delta *, unsigned int raw_sample);
	bool has_registers;
	unsigned int addr_shift;
	unsigned int read_mask;
};

/**
 * struct ad_sigma_delta - Sigma Delta device struct
 * @spi: The spi device associated with the Sigma Delta device.
 * @trig: The IIO trigger associated with the Sigma Delta device.
 *
 * Most of the fields are private to the sigma delta library code and should not
 * be accessed by individual drivers.
 */
struct ad_sigma_delta {
	struct spi_device	*spi;
	struct iio_trigger	*trig;

/* private: */
	struct completion	completion;
	bool			irq_dis;

	bool			bus_locked;

	uint8_t			comm;

	const struct ad_sigma_delta_info *info;

	/*
	 * DMA (thus cache coherency maintenance) requires the
	 * transfer buffers to live in their own cache lines.
	 */
	uint8_t				data[4] ____cacheline_aligned;
};

static inline int ad_sigma_delta_set_channel(struct ad_sigma_delta *sd,
	unsigned int channel)
{
	if (sd->info->set_channel)
		return sd->info->set_channel(sd, channel);

	return 0;
}

static inline int ad_sigma_delta_set_mode(struct ad_sigma_delta *sd,
	unsigned int mode)
{
	if (sd->info->set_mode)
		return sd->info->set_mode(sd, mode);

	return 0;
}

static inline int ad_sigma_delta_postprocess_sample(struct ad_sigma_delta *sd,
	unsigned int raw_sample)
{
	if (sd->info->postprocess_sample)
		return sd->info->postprocess_sample(sd, raw_sample);

	return 0;
}

void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm);
int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
	unsigned int size, unsigned int val);
int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
	unsigned int size, unsigned int *val);

int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
	const struct iio_chan_spec *chan, int *val);
int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
	const struct ad_sd_calib_data *cd, unsigned int n);
int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
	struct spi_device *spi, const struct ad_sigma_delta_info *info);

int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev);
void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev);

int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig);

#define __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
	_storagebits, _shift, _extend_name, _type) \
	{ \
		.type = (_type), \
		.differential = (_channel2 == -1 ? 0 : 1), \
		.indexed = 1, \
		.channel = (_channel1), \
		.channel2 = (_channel2), \
		.address = (_address), \
		.extend_name = (_extend_name), \
		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
			BIT(IIO_CHAN_INFO_OFFSET), \
		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
		.scan_index = (_si), \
		.scan_type = { \
			.sign = 'u', \
			.realbits = (_bits), \
			.storagebits = (_storagebits), \
			.shift = (_shift), \
			.endianness = IIO_BE, \
		}, \
	}

#define AD_SD_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
	_storagebits, _shift) \
	__AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
		_storagebits, _shift, NULL, IIO_VOLTAGE)

#define AD_SD_SHORTED_CHANNEL(_si, _channel, _address, _bits, \
	_storagebits, _shift) \
	__AD_SD_CHANNEL(_si, _channel, _channel, _address, _bits, \
		_storagebits, _shift, "shorted", IIO_VOLTAGE)

#define AD_SD_CHANNEL(_si, _channel, _address, _bits, \
	_storagebits, _shift) \
	__AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
		_storagebits, _shift, NULL, IIO_VOLTAGE)

#define AD_SD_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \
	__AD_SD_CHANNEL(_si, 0, -1, _address, _bits, \
		_storagebits, _shift, NULL, IIO_TEMP)

#define AD_SD_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \
	_shift) \
	__AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
		_storagebits, _shift, "supply", IIO_VOLTAGE)

#endif