1955c2aa9SWilliam Breathitt Gray // SPDX-License-Identifier: GPL-2.0-only
2955c2aa9SWilliam Breathitt Gray /*
3955c2aa9SWilliam Breathitt Gray * IIO driver for the Apex Embedded Systems STX104
4955c2aa9SWilliam Breathitt Gray * Copyright (C) 2016 William Breathitt Gray
5955c2aa9SWilliam Breathitt Gray */
6c7301b84SWilliam Breathitt Gray #include <linux/bitfield.h>
7aec463feSWilliam Breathitt Gray #include <linux/bits.h>
8955c2aa9SWilliam Breathitt Gray #include <linux/device.h>
9c7301b84SWilliam Breathitt Gray #include <linux/err.h>
10c7301b84SWilliam Breathitt Gray #include <linux/gpio/regmap.h>
11955c2aa9SWilliam Breathitt Gray #include <linux/iio/iio.h>
12955c2aa9SWilliam Breathitt Gray #include <linux/iio/types.h>
13955c2aa9SWilliam Breathitt Gray #include <linux/isa.h>
14955c2aa9SWilliam Breathitt Gray #include <linux/kernel.h>
1546a4cac7SWilliam Breathitt Gray #include <linux/limits.h>
16955c2aa9SWilliam Breathitt Gray #include <linux/module.h>
17955c2aa9SWilliam Breathitt Gray #include <linux/moduleparam.h>
1897408274SWilliam Breathitt Gray #include <linux/mutex.h>
19c7301b84SWilliam Breathitt Gray #include <linux/regmap.h>
20955c2aa9SWilliam Breathitt Gray #include <linux/types.h>
21955c2aa9SWilliam Breathitt Gray
22955c2aa9SWilliam Breathitt Gray #define STX104_OUT_CHAN(chan) { \
23955c2aa9SWilliam Breathitt Gray .type = IIO_VOLTAGE, \
24955c2aa9SWilliam Breathitt Gray .channel = chan, \
25955c2aa9SWilliam Breathitt Gray .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
26955c2aa9SWilliam Breathitt Gray .indexed = 1, \
27955c2aa9SWilliam Breathitt Gray .output = 1 \
28955c2aa9SWilliam Breathitt Gray }
29955c2aa9SWilliam Breathitt Gray #define STX104_IN_CHAN(chan, diff) { \
30955c2aa9SWilliam Breathitt Gray .type = IIO_VOLTAGE, \
31955c2aa9SWilliam Breathitt Gray .channel = chan, \
32955c2aa9SWilliam Breathitt Gray .channel2 = chan, \
33955c2aa9SWilliam Breathitt Gray .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
34955c2aa9SWilliam Breathitt Gray BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \
35955c2aa9SWilliam Breathitt Gray .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
36955c2aa9SWilliam Breathitt Gray .indexed = 1, \
37955c2aa9SWilliam Breathitt Gray .differential = diff \
38955c2aa9SWilliam Breathitt Gray }
39955c2aa9SWilliam Breathitt Gray
40955c2aa9SWilliam Breathitt Gray #define STX104_NUM_OUT_CHAN 2
41955c2aa9SWilliam Breathitt Gray
42955c2aa9SWilliam Breathitt Gray #define STX104_EXTENT 16
43955c2aa9SWilliam Breathitt Gray
44955c2aa9SWilliam Breathitt Gray static unsigned int base[max_num_isa_dev(STX104_EXTENT)];
45955c2aa9SWilliam Breathitt Gray static unsigned int num_stx104;
46955c2aa9SWilliam Breathitt Gray module_param_hw_array(base, uint, ioport, &num_stx104, 0);
47955c2aa9SWilliam Breathitt Gray MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
48955c2aa9SWilliam Breathitt Gray
49c7301b84SWilliam Breathitt Gray #define STX104_AIO_BASE 0x0
50c7301b84SWilliam Breathitt Gray #define STX104_SOFTWARE_STROBE STX104_AIO_BASE
51c7301b84SWilliam Breathitt Gray #define STX104_ADC_DATA STX104_AIO_BASE
52c7301b84SWilliam Breathitt Gray #define STX104_ADC_CHANNEL (STX104_AIO_BASE + 0x2)
53c7301b84SWilliam Breathitt Gray #define STX104_DIO_REG (STX104_AIO_BASE + 0x3)
54c7301b84SWilliam Breathitt Gray #define STX104_DAC_BASE (STX104_AIO_BASE + 0x4)
55c7301b84SWilliam Breathitt Gray #define STX104_ADC_STATUS (STX104_AIO_BASE + 0x8)
56c7301b84SWilliam Breathitt Gray #define STX104_ADC_CONTROL (STX104_AIO_BASE + 0x9)
57c7301b84SWilliam Breathitt Gray #define STX104_ADC_CONFIGURATION (STX104_AIO_BASE + 0x11)
58c7301b84SWilliam Breathitt Gray
59c7301b84SWilliam Breathitt Gray #define STX104_AIO_DATA_STRIDE 2
60c7301b84SWilliam Breathitt Gray #define STX104_DAC_OFFSET(_channel) (STX104_DAC_BASE + STX104_AIO_DATA_STRIDE * (_channel))
61c7301b84SWilliam Breathitt Gray
62c7301b84SWilliam Breathitt Gray /* ADC Channel */
63c7301b84SWilliam Breathitt Gray #define STX104_FC GENMASK(3, 0)
64c7301b84SWilliam Breathitt Gray #define STX104_LC GENMASK(7, 4)
65c7301b84SWilliam Breathitt Gray #define STX104_SINGLE_CHANNEL(_channel) \
66c7301b84SWilliam Breathitt Gray (u8_encode_bits(_channel, STX104_FC) | u8_encode_bits(_channel, STX104_LC))
67c7301b84SWilliam Breathitt Gray
68c7301b84SWilliam Breathitt Gray /* ADC Status */
69c7301b84SWilliam Breathitt Gray #define STX104_SD BIT(5)
70c7301b84SWilliam Breathitt Gray #define STX104_CNV BIT(7)
71c7301b84SWilliam Breathitt Gray #define STX104_DIFFERENTIAL 1
72c7301b84SWilliam Breathitt Gray
73c7301b84SWilliam Breathitt Gray /* ADC Control */
74c7301b84SWilliam Breathitt Gray #define STX104_ALSS GENMASK(1, 0)
75c7301b84SWilliam Breathitt Gray #define STX104_SOFTWARE_TRIGGER u8_encode_bits(0x0, STX104_ALSS)
76c7301b84SWilliam Breathitt Gray
77c7301b84SWilliam Breathitt Gray /* ADC Configuration */
78c7301b84SWilliam Breathitt Gray #define STX104_GAIN GENMASK(1, 0)
79c7301b84SWilliam Breathitt Gray #define STX104_ADBU BIT(2)
80c7301b84SWilliam Breathitt Gray #define STX104_BIPOLAR 0
81c7301b84SWilliam Breathitt Gray #define STX104_GAIN_X1 0
82c7301b84SWilliam Breathitt Gray #define STX104_GAIN_X2 1
83c7301b84SWilliam Breathitt Gray #define STX104_GAIN_X4 2
84c7301b84SWilliam Breathitt Gray #define STX104_GAIN_X8 3
85955c2aa9SWilliam Breathitt Gray
86955c2aa9SWilliam Breathitt Gray /**
87955c2aa9SWilliam Breathitt Gray * struct stx104_iio - IIO device private data structure
8897408274SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions
89c7301b84SWilliam Breathitt Gray * @aio_data_map: Regmap for analog I/O data
90c7301b84SWilliam Breathitt Gray * @aio_ctl_map: Regmap for analog I/O control
91955c2aa9SWilliam Breathitt Gray */
92955c2aa9SWilliam Breathitt Gray struct stx104_iio {
9397408274SWilliam Breathitt Gray struct mutex lock;
94c7301b84SWilliam Breathitt Gray struct regmap *aio_data_map;
95c7301b84SWilliam Breathitt Gray struct regmap *aio_ctl_map;
96955c2aa9SWilliam Breathitt Gray };
97955c2aa9SWilliam Breathitt Gray
98c7301b84SWilliam Breathitt Gray static const struct regmap_range aio_ctl_wr_ranges[] = {
99c7301b84SWilliam Breathitt Gray regmap_reg_range(0x0, 0x0), regmap_reg_range(0x2, 0x2), regmap_reg_range(0x9, 0x9),
100c7301b84SWilliam Breathitt Gray regmap_reg_range(0x11, 0x11),
101c7301b84SWilliam Breathitt Gray };
102c7301b84SWilliam Breathitt Gray static const struct regmap_range aio_ctl_rd_ranges[] = {
103c7301b84SWilliam Breathitt Gray regmap_reg_range(0x2, 0x2), regmap_reg_range(0x8, 0x9), regmap_reg_range(0x11, 0x11),
104c7301b84SWilliam Breathitt Gray };
105c7301b84SWilliam Breathitt Gray static const struct regmap_range aio_ctl_volatile_ranges[] = {
106c7301b84SWilliam Breathitt Gray regmap_reg_range(0x8, 0x8),
107c7301b84SWilliam Breathitt Gray };
108c7301b84SWilliam Breathitt Gray static const struct regmap_access_table aio_ctl_wr_table = {
109c7301b84SWilliam Breathitt Gray .yes_ranges = aio_ctl_wr_ranges,
110c7301b84SWilliam Breathitt Gray .n_yes_ranges = ARRAY_SIZE(aio_ctl_wr_ranges),
111c7301b84SWilliam Breathitt Gray };
112c7301b84SWilliam Breathitt Gray static const struct regmap_access_table aio_ctl_rd_table = {
113c7301b84SWilliam Breathitt Gray .yes_ranges = aio_ctl_rd_ranges,
114c7301b84SWilliam Breathitt Gray .n_yes_ranges = ARRAY_SIZE(aio_ctl_rd_ranges),
115c7301b84SWilliam Breathitt Gray };
116c7301b84SWilliam Breathitt Gray static const struct regmap_access_table aio_ctl_volatile_table = {
117c7301b84SWilliam Breathitt Gray .yes_ranges = aio_ctl_volatile_ranges,
118c7301b84SWilliam Breathitt Gray .n_yes_ranges = ARRAY_SIZE(aio_ctl_volatile_ranges),
119c7301b84SWilliam Breathitt Gray };
120c7301b84SWilliam Breathitt Gray
121c7301b84SWilliam Breathitt Gray static const struct regmap_config aio_ctl_regmap_config = {
122c7301b84SWilliam Breathitt Gray .name = "aio_ctl",
123c7301b84SWilliam Breathitt Gray .reg_bits = 8,
124c7301b84SWilliam Breathitt Gray .reg_stride = 1,
125c7301b84SWilliam Breathitt Gray .reg_base = STX104_AIO_BASE,
126c7301b84SWilliam Breathitt Gray .val_bits = 8,
127c7301b84SWilliam Breathitt Gray .io_port = true,
128c7301b84SWilliam Breathitt Gray .wr_table = &aio_ctl_wr_table,
129c7301b84SWilliam Breathitt Gray .rd_table = &aio_ctl_rd_table,
130c7301b84SWilliam Breathitt Gray .volatile_table = &aio_ctl_volatile_table,
131c7301b84SWilliam Breathitt Gray .cache_type = REGCACHE_FLAT,
132c7301b84SWilliam Breathitt Gray };
133c7301b84SWilliam Breathitt Gray
134c7301b84SWilliam Breathitt Gray static const struct regmap_range aio_data_wr_ranges[] = {
135c7301b84SWilliam Breathitt Gray regmap_reg_range(0x4, 0x6),
136c7301b84SWilliam Breathitt Gray };
137c7301b84SWilliam Breathitt Gray static const struct regmap_range aio_data_rd_ranges[] = {
138c7301b84SWilliam Breathitt Gray regmap_reg_range(0x0, 0x0),
139c7301b84SWilliam Breathitt Gray };
140c7301b84SWilliam Breathitt Gray static const struct regmap_access_table aio_data_wr_table = {
141c7301b84SWilliam Breathitt Gray .yes_ranges = aio_data_wr_ranges,
142c7301b84SWilliam Breathitt Gray .n_yes_ranges = ARRAY_SIZE(aio_data_wr_ranges),
143c7301b84SWilliam Breathitt Gray };
144c7301b84SWilliam Breathitt Gray static const struct regmap_access_table aio_data_rd_table = {
145c7301b84SWilliam Breathitt Gray .yes_ranges = aio_data_rd_ranges,
146c7301b84SWilliam Breathitt Gray .n_yes_ranges = ARRAY_SIZE(aio_data_rd_ranges),
147c7301b84SWilliam Breathitt Gray };
148c7301b84SWilliam Breathitt Gray
149c7301b84SWilliam Breathitt Gray static const struct regmap_config aio_data_regmap_config = {
150c7301b84SWilliam Breathitt Gray .name = "aio_data",
151c7301b84SWilliam Breathitt Gray .reg_bits = 16,
152c7301b84SWilliam Breathitt Gray .reg_stride = STX104_AIO_DATA_STRIDE,
153c7301b84SWilliam Breathitt Gray .reg_base = STX104_AIO_BASE,
154c7301b84SWilliam Breathitt Gray .val_bits = 16,
155c7301b84SWilliam Breathitt Gray .io_port = true,
156c7301b84SWilliam Breathitt Gray .wr_table = &aio_data_wr_table,
157c7301b84SWilliam Breathitt Gray .rd_table = &aio_data_rd_table,
158c7301b84SWilliam Breathitt Gray .volatile_table = &aio_data_rd_table,
159c7301b84SWilliam Breathitt Gray .cache_type = REGCACHE_FLAT,
160c7301b84SWilliam Breathitt Gray };
161c7301b84SWilliam Breathitt Gray
162c7301b84SWilliam Breathitt Gray static const struct regmap_config dio_regmap_config = {
163c7301b84SWilliam Breathitt Gray .name = "dio",
164c7301b84SWilliam Breathitt Gray .reg_bits = 8,
165c7301b84SWilliam Breathitt Gray .reg_stride = 1,
166c7301b84SWilliam Breathitt Gray .reg_base = STX104_DIO_REG,
167c7301b84SWilliam Breathitt Gray .val_bits = 8,
168c7301b84SWilliam Breathitt Gray .io_port = true,
169955c2aa9SWilliam Breathitt Gray };
170955c2aa9SWilliam Breathitt Gray
stx104_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)171955c2aa9SWilliam Breathitt Gray static int stx104_read_raw(struct iio_dev *indio_dev,
172955c2aa9SWilliam Breathitt Gray struct iio_chan_spec const *chan, int *val, int *val2, long mask)
173955c2aa9SWilliam Breathitt Gray {
174955c2aa9SWilliam Breathitt Gray struct stx104_iio *const priv = iio_priv(indio_dev);
175c7301b84SWilliam Breathitt Gray int err;
176955c2aa9SWilliam Breathitt Gray unsigned int adc_config;
177c7301b84SWilliam Breathitt Gray unsigned int value;
178c7301b84SWilliam Breathitt Gray unsigned int adc_status;
179955c2aa9SWilliam Breathitt Gray
180955c2aa9SWilliam Breathitt Gray switch (mask) {
181955c2aa9SWilliam Breathitt Gray case IIO_CHAN_INFO_HARDWAREGAIN:
182c7301b84SWilliam Breathitt Gray err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config);
183c7301b84SWilliam Breathitt Gray if (err)
184c7301b84SWilliam Breathitt Gray return err;
185955c2aa9SWilliam Breathitt Gray
186c7301b84SWilliam Breathitt Gray *val = BIT(u8_get_bits(adc_config, STX104_GAIN));
187955c2aa9SWilliam Breathitt Gray return IIO_VAL_INT;
188955c2aa9SWilliam Breathitt Gray case IIO_CHAN_INFO_RAW:
189955c2aa9SWilliam Breathitt Gray if (chan->output) {
190c7301b84SWilliam Breathitt Gray err = regmap_read(priv->aio_data_map, STX104_DAC_OFFSET(chan->channel),
191c7301b84SWilliam Breathitt Gray &value);
192c7301b84SWilliam Breathitt Gray if (err)
193c7301b84SWilliam Breathitt Gray return err;
194c7301b84SWilliam Breathitt Gray *val = value;
195955c2aa9SWilliam Breathitt Gray return IIO_VAL_INT;
196955c2aa9SWilliam Breathitt Gray }
197955c2aa9SWilliam Breathitt Gray
1984f9b80aeSWilliam Breathitt Gray mutex_lock(&priv->lock);
1994f9b80aeSWilliam Breathitt Gray
200955c2aa9SWilliam Breathitt Gray /* select ADC channel */
201c7301b84SWilliam Breathitt Gray err = regmap_write(priv->aio_ctl_map, STX104_ADC_CHANNEL,
202c7301b84SWilliam Breathitt Gray STX104_SINGLE_CHANNEL(chan->channel));
203c7301b84SWilliam Breathitt Gray if (err) {
204c7301b84SWilliam Breathitt Gray mutex_unlock(&priv->lock);
205c7301b84SWilliam Breathitt Gray return err;
206c7301b84SWilliam Breathitt Gray }
207955c2aa9SWilliam Breathitt Gray
208*7c95a3f5SWilliam Breathitt Gray /*
209*7c95a3f5SWilliam Breathitt Gray * Trigger ADC sample capture by writing to the 8-bit Software Strobe Register and
210*7c95a3f5SWilliam Breathitt Gray * wait for completion; the conversion time range is 5 microseconds to 53.68 seconds
211*7c95a3f5SWilliam Breathitt Gray * in steps of 25 nanoseconds. The actual Analog Input Frame Timer time interval is
212*7c95a3f5SWilliam Breathitt Gray * calculated as:
213*7c95a3f5SWilliam Breathitt Gray * ai_time_frame_ns = ( AIFT + 1 ) * ( 25 nanoseconds ).
214*7c95a3f5SWilliam Breathitt Gray * Where 0 <= AIFT <= 2147483648.
215955c2aa9SWilliam Breathitt Gray */
216c7301b84SWilliam Breathitt Gray err = regmap_write(priv->aio_ctl_map, STX104_SOFTWARE_STROBE, 0);
217c7301b84SWilliam Breathitt Gray if (err) {
218c7301b84SWilliam Breathitt Gray mutex_unlock(&priv->lock);
219c7301b84SWilliam Breathitt Gray return err;
220c7301b84SWilliam Breathitt Gray }
221*7c95a3f5SWilliam Breathitt Gray err = regmap_read_poll_timeout(priv->aio_ctl_map, STX104_ADC_STATUS, adc_status,
222*7c95a3f5SWilliam Breathitt Gray !u8_get_bits(adc_status, STX104_CNV), 0, 53687092);
223c7301b84SWilliam Breathitt Gray if (err) {
224c7301b84SWilliam Breathitt Gray mutex_unlock(&priv->lock);
225c7301b84SWilliam Breathitt Gray return err;
226c7301b84SWilliam Breathitt Gray }
227955c2aa9SWilliam Breathitt Gray
228c7301b84SWilliam Breathitt Gray err = regmap_read(priv->aio_data_map, STX104_ADC_DATA, &value);
229c7301b84SWilliam Breathitt Gray if (err) {
230c7301b84SWilliam Breathitt Gray mutex_unlock(&priv->lock);
231c7301b84SWilliam Breathitt Gray return err;
232c7301b84SWilliam Breathitt Gray }
233c7301b84SWilliam Breathitt Gray *val = value;
2344f9b80aeSWilliam Breathitt Gray
2354f9b80aeSWilliam Breathitt Gray mutex_unlock(&priv->lock);
236955c2aa9SWilliam Breathitt Gray return IIO_VAL_INT;
237955c2aa9SWilliam Breathitt Gray case IIO_CHAN_INFO_OFFSET:
238955c2aa9SWilliam Breathitt Gray /* get ADC bipolar/unipolar configuration */
239c7301b84SWilliam Breathitt Gray err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config);
240c7301b84SWilliam Breathitt Gray if (err)
241c7301b84SWilliam Breathitt Gray return err;
242955c2aa9SWilliam Breathitt Gray
243c7301b84SWilliam Breathitt Gray *val = (u8_get_bits(adc_config, STX104_ADBU) == STX104_BIPOLAR) ? -32768 : 0;
244955c2aa9SWilliam Breathitt Gray return IIO_VAL_INT;
245955c2aa9SWilliam Breathitt Gray case IIO_CHAN_INFO_SCALE:
246955c2aa9SWilliam Breathitt Gray /* get ADC bipolar/unipolar and gain configuration */
247c7301b84SWilliam Breathitt Gray err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config);
248c7301b84SWilliam Breathitt Gray if (err)
249c7301b84SWilliam Breathitt Gray return err;
250955c2aa9SWilliam Breathitt Gray
251955c2aa9SWilliam Breathitt Gray *val = 5;
252c7301b84SWilliam Breathitt Gray *val2 = (u8_get_bits(adc_config, STX104_ADBU) == STX104_BIPOLAR) ? 14 : 15;
253c7301b84SWilliam Breathitt Gray *val2 += u8_get_bits(adc_config, STX104_GAIN);
254955c2aa9SWilliam Breathitt Gray return IIO_VAL_FRACTIONAL_LOG2;
255955c2aa9SWilliam Breathitt Gray }
256955c2aa9SWilliam Breathitt Gray
257955c2aa9SWilliam Breathitt Gray return -EINVAL;
258955c2aa9SWilliam Breathitt Gray }
259955c2aa9SWilliam Breathitt Gray
stx104_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)260955c2aa9SWilliam Breathitt Gray static int stx104_write_raw(struct iio_dev *indio_dev,
261955c2aa9SWilliam Breathitt Gray struct iio_chan_spec const *chan, int val, int val2, long mask)
262955c2aa9SWilliam Breathitt Gray {
263955c2aa9SWilliam Breathitt Gray struct stx104_iio *const priv = iio_priv(indio_dev);
264c7301b84SWilliam Breathitt Gray u8 gain;
265955c2aa9SWilliam Breathitt Gray
266955c2aa9SWilliam Breathitt Gray switch (mask) {
267955c2aa9SWilliam Breathitt Gray case IIO_CHAN_INFO_HARDWAREGAIN:
268955c2aa9SWilliam Breathitt Gray /* Only four gain states (x1, x2, x4, x8) */
269955c2aa9SWilliam Breathitt Gray switch (val) {
270955c2aa9SWilliam Breathitt Gray case 1:
271c7301b84SWilliam Breathitt Gray gain = STX104_GAIN_X1;
272955c2aa9SWilliam Breathitt Gray break;
273955c2aa9SWilliam Breathitt Gray case 2:
274c7301b84SWilliam Breathitt Gray gain = STX104_GAIN_X2;
275955c2aa9SWilliam Breathitt Gray break;
276955c2aa9SWilliam Breathitt Gray case 4:
277c7301b84SWilliam Breathitt Gray gain = STX104_GAIN_X4;
278955c2aa9SWilliam Breathitt Gray break;
279955c2aa9SWilliam Breathitt Gray case 8:
280c7301b84SWilliam Breathitt Gray gain = STX104_GAIN_X8;
281955c2aa9SWilliam Breathitt Gray break;
282955c2aa9SWilliam Breathitt Gray default:
283955c2aa9SWilliam Breathitt Gray return -EINVAL;
284955c2aa9SWilliam Breathitt Gray }
285955c2aa9SWilliam Breathitt Gray
286c7301b84SWilliam Breathitt Gray return regmap_write(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, gain);
287955c2aa9SWilliam Breathitt Gray case IIO_CHAN_INFO_RAW:
288a94abc74SWilliam Breathitt Gray if (!chan->output)
289a94abc74SWilliam Breathitt Gray return -EINVAL;
290a94abc74SWilliam Breathitt Gray
29146a4cac7SWilliam Breathitt Gray if (val < 0 || val > U16_MAX)
292955c2aa9SWilliam Breathitt Gray return -EINVAL;
293955c2aa9SWilliam Breathitt Gray
294c7301b84SWilliam Breathitt Gray return regmap_write(priv->aio_data_map, STX104_DAC_OFFSET(chan->channel), val);
295955c2aa9SWilliam Breathitt Gray }
296955c2aa9SWilliam Breathitt Gray
297955c2aa9SWilliam Breathitt Gray return -EINVAL;
298955c2aa9SWilliam Breathitt Gray }
299955c2aa9SWilliam Breathitt Gray
300955c2aa9SWilliam Breathitt Gray static const struct iio_info stx104_info = {
301955c2aa9SWilliam Breathitt Gray .read_raw = stx104_read_raw,
302955c2aa9SWilliam Breathitt Gray .write_raw = stx104_write_raw
303955c2aa9SWilliam Breathitt Gray };
304955c2aa9SWilliam Breathitt Gray
305955c2aa9SWilliam Breathitt Gray /* single-ended input channels configuration */
306955c2aa9SWilliam Breathitt Gray static const struct iio_chan_spec stx104_channels_sing[] = {
307955c2aa9SWilliam Breathitt Gray STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
308955c2aa9SWilliam Breathitt Gray STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0),
309955c2aa9SWilliam Breathitt Gray STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0),
310955c2aa9SWilliam Breathitt Gray STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0),
311955c2aa9SWilliam Breathitt Gray STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0),
312955c2aa9SWilliam Breathitt Gray STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0),
313955c2aa9SWilliam Breathitt Gray STX104_IN_CHAN(15, 0)
314955c2aa9SWilliam Breathitt Gray };
315955c2aa9SWilliam Breathitt Gray /* differential input channels configuration */
316955c2aa9SWilliam Breathitt Gray static const struct iio_chan_spec stx104_channels_diff[] = {
317955c2aa9SWilliam Breathitt Gray STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
318955c2aa9SWilliam Breathitt Gray STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1),
319955c2aa9SWilliam Breathitt Gray STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1),
320955c2aa9SWilliam Breathitt Gray STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
321955c2aa9SWilliam Breathitt Gray };
322955c2aa9SWilliam Breathitt Gray
stx104_reg_mask_xlate(struct gpio_regmap * const gpio,const unsigned int base,unsigned int offset,unsigned int * const reg,unsigned int * const mask)323c7301b84SWilliam Breathitt Gray static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
324c7301b84SWilliam Breathitt Gray unsigned int offset, unsigned int *const reg,
325c7301b84SWilliam Breathitt Gray unsigned int *const mask)
326955c2aa9SWilliam Breathitt Gray {
327c7301b84SWilliam Breathitt Gray /* Output lines are located at same register bit offsets as input lines */
328955c2aa9SWilliam Breathitt Gray if (offset >= 4)
329c7301b84SWilliam Breathitt Gray offset -= 4;
330c7301b84SWilliam Breathitt Gray
331c7301b84SWilliam Breathitt Gray *reg = base;
332c7301b84SWilliam Breathitt Gray *mask = BIT(offset);
333955c2aa9SWilliam Breathitt Gray
334955c2aa9SWilliam Breathitt Gray return 0;
335955c2aa9SWilliam Breathitt Gray }
336955c2aa9SWilliam Breathitt Gray
337955c2aa9SWilliam Breathitt Gray #define STX104_NGPIO 8
338955c2aa9SWilliam Breathitt Gray static const char *stx104_names[STX104_NGPIO] = {
339955c2aa9SWilliam Breathitt Gray "DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"
340955c2aa9SWilliam Breathitt Gray };
341955c2aa9SWilliam Breathitt Gray
stx104_init_hw(struct stx104_iio * const priv)342c7301b84SWilliam Breathitt Gray static int stx104_init_hw(struct stx104_iio *const priv)
343955c2aa9SWilliam Breathitt Gray {
344c7301b84SWilliam Breathitt Gray int err;
345955c2aa9SWilliam Breathitt Gray
346c7301b84SWilliam Breathitt Gray /* configure device for software trigger operation */
347c7301b84SWilliam Breathitt Gray err = regmap_write(priv->aio_ctl_map, STX104_ADC_CONTROL, STX104_SOFTWARE_TRIGGER);
348c7301b84SWilliam Breathitt Gray if (err)
349c7301b84SWilliam Breathitt Gray return err;
350955c2aa9SWilliam Breathitt Gray
351c7301b84SWilliam Breathitt Gray /* initialize gain setting to x1 */
352c7301b84SWilliam Breathitt Gray err = regmap_write(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, STX104_GAIN_X1);
353c7301b84SWilliam Breathitt Gray if (err)
354c7301b84SWilliam Breathitt Gray return err;
355955c2aa9SWilliam Breathitt Gray
356c7301b84SWilliam Breathitt Gray /* initialize DAC outputs to 0V */
357c7301b84SWilliam Breathitt Gray err = regmap_write(priv->aio_data_map, STX104_DAC_BASE, 0);
358c7301b84SWilliam Breathitt Gray if (err)
359c7301b84SWilliam Breathitt Gray return err;
360c7301b84SWilliam Breathitt Gray err = regmap_write(priv->aio_data_map, STX104_DAC_BASE + STX104_AIO_DATA_STRIDE, 0);
361c7301b84SWilliam Breathitt Gray if (err)
362c7301b84SWilliam Breathitt Gray return err;
363955c2aa9SWilliam Breathitt Gray
364c7301b84SWilliam Breathitt Gray return 0;
365955c2aa9SWilliam Breathitt Gray }
366955c2aa9SWilliam Breathitt Gray
stx104_probe(struct device * dev,unsigned int id)367955c2aa9SWilliam Breathitt Gray static int stx104_probe(struct device *dev, unsigned int id)
368955c2aa9SWilliam Breathitt Gray {
369955c2aa9SWilliam Breathitt Gray struct iio_dev *indio_dev;
370955c2aa9SWilliam Breathitt Gray struct stx104_iio *priv;
371c7301b84SWilliam Breathitt Gray struct gpio_regmap_config gpio_config;
372c7301b84SWilliam Breathitt Gray void __iomem *stx104_base;
373c7301b84SWilliam Breathitt Gray struct regmap *aio_ctl_map;
374c7301b84SWilliam Breathitt Gray struct regmap *aio_data_map;
375c7301b84SWilliam Breathitt Gray struct regmap *dio_map;
376955c2aa9SWilliam Breathitt Gray int err;
377c7301b84SWilliam Breathitt Gray unsigned int adc_status;
378955c2aa9SWilliam Breathitt Gray
379955c2aa9SWilliam Breathitt Gray indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
380955c2aa9SWilliam Breathitt Gray if (!indio_dev)
381955c2aa9SWilliam Breathitt Gray return -ENOMEM;
382955c2aa9SWilliam Breathitt Gray
383955c2aa9SWilliam Breathitt Gray if (!devm_request_region(dev, base[id], STX104_EXTENT,
384955c2aa9SWilliam Breathitt Gray dev_name(dev))) {
385955c2aa9SWilliam Breathitt Gray dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
386955c2aa9SWilliam Breathitt Gray base[id], base[id] + STX104_EXTENT);
387955c2aa9SWilliam Breathitt Gray return -EBUSY;
388955c2aa9SWilliam Breathitt Gray }
389955c2aa9SWilliam Breathitt Gray
390c7301b84SWilliam Breathitt Gray stx104_base = devm_ioport_map(dev, base[id], STX104_EXTENT);
391c7301b84SWilliam Breathitt Gray if (!stx104_base)
392955c2aa9SWilliam Breathitt Gray return -ENOMEM;
393955c2aa9SWilliam Breathitt Gray
394c7301b84SWilliam Breathitt Gray aio_ctl_map = devm_regmap_init_mmio(dev, stx104_base, &aio_ctl_regmap_config);
395c7301b84SWilliam Breathitt Gray if (IS_ERR(aio_ctl_map))
396c7301b84SWilliam Breathitt Gray return dev_err_probe(dev, PTR_ERR(aio_ctl_map),
397c7301b84SWilliam Breathitt Gray "Unable to initialize aio_ctl register map\n");
398c7301b84SWilliam Breathitt Gray
399c7301b84SWilliam Breathitt Gray aio_data_map = devm_regmap_init_mmio(dev, stx104_base, &aio_data_regmap_config);
400c7301b84SWilliam Breathitt Gray if (IS_ERR(aio_data_map))
401c7301b84SWilliam Breathitt Gray return dev_err_probe(dev, PTR_ERR(aio_data_map),
402c7301b84SWilliam Breathitt Gray "Unable to initialize aio_data register map\n");
403c7301b84SWilliam Breathitt Gray
404c7301b84SWilliam Breathitt Gray dio_map = devm_regmap_init_mmio(dev, stx104_base, &dio_regmap_config);
405c7301b84SWilliam Breathitt Gray if (IS_ERR(dio_map))
406c7301b84SWilliam Breathitt Gray return dev_err_probe(dev, PTR_ERR(dio_map),
407c7301b84SWilliam Breathitt Gray "Unable to initialize dio register map\n");
408c7301b84SWilliam Breathitt Gray
409c7301b84SWilliam Breathitt Gray priv = iio_priv(indio_dev);
410c7301b84SWilliam Breathitt Gray priv->aio_ctl_map = aio_ctl_map;
411c7301b84SWilliam Breathitt Gray priv->aio_data_map = aio_data_map;
412c7301b84SWilliam Breathitt Gray
413955c2aa9SWilliam Breathitt Gray indio_dev->info = &stx104_info;
414955c2aa9SWilliam Breathitt Gray indio_dev->modes = INDIO_DIRECT_MODE;
415955c2aa9SWilliam Breathitt Gray
416c7301b84SWilliam Breathitt Gray err = regmap_read(aio_ctl_map, STX104_ADC_STATUS, &adc_status);
417c7301b84SWilliam Breathitt Gray if (err)
418c7301b84SWilliam Breathitt Gray return err;
419c7301b84SWilliam Breathitt Gray
420c7301b84SWilliam Breathitt Gray if (u8_get_bits(adc_status, STX104_SD) == STX104_DIFFERENTIAL) {
421955c2aa9SWilliam Breathitt Gray indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff);
422955c2aa9SWilliam Breathitt Gray indio_dev->channels = stx104_channels_diff;
423955c2aa9SWilliam Breathitt Gray } else {
424955c2aa9SWilliam Breathitt Gray indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing);
425955c2aa9SWilliam Breathitt Gray indio_dev->channels = stx104_channels_sing;
426955c2aa9SWilliam Breathitt Gray }
427955c2aa9SWilliam Breathitt Gray
428955c2aa9SWilliam Breathitt Gray indio_dev->name = dev_name(dev);
429955c2aa9SWilliam Breathitt Gray
43097408274SWilliam Breathitt Gray mutex_init(&priv->lock);
43197408274SWilliam Breathitt Gray
432c7301b84SWilliam Breathitt Gray err = stx104_init_hw(priv);
433c7301b84SWilliam Breathitt Gray if (err)
434955c2aa9SWilliam Breathitt Gray return err;
435955c2aa9SWilliam Breathitt Gray
436c7301b84SWilliam Breathitt Gray err = devm_iio_device_register(dev, indio_dev);
437c7301b84SWilliam Breathitt Gray if (err)
438c7301b84SWilliam Breathitt Gray return err;
439c7301b84SWilliam Breathitt Gray
440c7301b84SWilliam Breathitt Gray gpio_config = (struct gpio_regmap_config) {
441c7301b84SWilliam Breathitt Gray .parent = dev,
442c7301b84SWilliam Breathitt Gray .regmap = dio_map,
443c7301b84SWilliam Breathitt Gray .ngpio = STX104_NGPIO,
444c7301b84SWilliam Breathitt Gray .names = stx104_names,
445c7301b84SWilliam Breathitt Gray .reg_dat_base = GPIO_REGMAP_ADDR(STX104_DIO_REG),
446c7301b84SWilliam Breathitt Gray .reg_set_base = GPIO_REGMAP_ADDR(STX104_DIO_REG),
447c7301b84SWilliam Breathitt Gray .ngpio_per_reg = STX104_NGPIO,
448c7301b84SWilliam Breathitt Gray .reg_mask_xlate = stx104_reg_mask_xlate,
449c7301b84SWilliam Breathitt Gray .drvdata = dio_map,
450c7301b84SWilliam Breathitt Gray };
451c7301b84SWilliam Breathitt Gray
452c7301b84SWilliam Breathitt Gray return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
453955c2aa9SWilliam Breathitt Gray }
454955c2aa9SWilliam Breathitt Gray
455955c2aa9SWilliam Breathitt Gray static struct isa_driver stx104_driver = {
456955c2aa9SWilliam Breathitt Gray .probe = stx104_probe,
457955c2aa9SWilliam Breathitt Gray .driver = {
458955c2aa9SWilliam Breathitt Gray .name = "stx104"
459955c2aa9SWilliam Breathitt Gray },
460955c2aa9SWilliam Breathitt Gray };
461955c2aa9SWilliam Breathitt Gray
462955c2aa9SWilliam Breathitt Gray module_isa_driver(stx104_driver, num_stx104);
463955c2aa9SWilliam Breathitt Gray
464955c2aa9SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
465955c2aa9SWilliam Breathitt Gray MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
466955c2aa9SWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
467