1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * IIO driver for the Apex Embedded Systems STX104
4*4882a593Smuzhiyun * Copyright (C) 2016 William Breathitt Gray
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun #include <linux/bitops.h>
7*4882a593Smuzhiyun #include <linux/device.h>
8*4882a593Smuzhiyun #include <linux/errno.h>
9*4882a593Smuzhiyun #include <linux/gpio/driver.h>
10*4882a593Smuzhiyun #include <linux/iio/iio.h>
11*4882a593Smuzhiyun #include <linux/iio/types.h>
12*4882a593Smuzhiyun #include <linux/io.h>
13*4882a593Smuzhiyun #include <linux/ioport.h>
14*4882a593Smuzhiyun #include <linux/isa.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/moduleparam.h>
18*4882a593Smuzhiyun #include <linux/spinlock.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define STX104_OUT_CHAN(chan) { \
21*4882a593Smuzhiyun .type = IIO_VOLTAGE, \
22*4882a593Smuzhiyun .channel = chan, \
23*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
24*4882a593Smuzhiyun .indexed = 1, \
25*4882a593Smuzhiyun .output = 1 \
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun #define STX104_IN_CHAN(chan, diff) { \
28*4882a593Smuzhiyun .type = IIO_VOLTAGE, \
29*4882a593Smuzhiyun .channel = chan, \
30*4882a593Smuzhiyun .channel2 = chan, \
31*4882a593Smuzhiyun .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
32*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \
33*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
34*4882a593Smuzhiyun .indexed = 1, \
35*4882a593Smuzhiyun .differential = diff \
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #define STX104_NUM_OUT_CHAN 2
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #define STX104_EXTENT 16
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static unsigned int base[max_num_isa_dev(STX104_EXTENT)];
43*4882a593Smuzhiyun static unsigned int num_stx104;
44*4882a593Smuzhiyun module_param_hw_array(base, uint, ioport, &num_stx104, 0);
45*4882a593Smuzhiyun MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /**
48*4882a593Smuzhiyun * struct stx104_iio - IIO device private data structure
49*4882a593Smuzhiyun * @chan_out_states: channels' output states
50*4882a593Smuzhiyun * @base: base port address of the IIO device
51*4882a593Smuzhiyun */
52*4882a593Smuzhiyun struct stx104_iio {
53*4882a593Smuzhiyun unsigned int chan_out_states[STX104_NUM_OUT_CHAN];
54*4882a593Smuzhiyun unsigned int base;
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /**
58*4882a593Smuzhiyun * struct stx104_gpio - GPIO device private data structure
59*4882a593Smuzhiyun * @chip: instance of the gpio_chip
60*4882a593Smuzhiyun * @lock: synchronization lock to prevent I/O race conditions
61*4882a593Smuzhiyun * @base: base port address of the GPIO device
62*4882a593Smuzhiyun * @out_state: output bits state
63*4882a593Smuzhiyun */
64*4882a593Smuzhiyun struct stx104_gpio {
65*4882a593Smuzhiyun struct gpio_chip chip;
66*4882a593Smuzhiyun spinlock_t lock;
67*4882a593Smuzhiyun unsigned int base;
68*4882a593Smuzhiyun unsigned int out_state;
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun
stx104_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)71*4882a593Smuzhiyun static int stx104_read_raw(struct iio_dev *indio_dev,
72*4882a593Smuzhiyun struct iio_chan_spec const *chan, int *val, int *val2, long mask)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun struct stx104_iio *const priv = iio_priv(indio_dev);
75*4882a593Smuzhiyun unsigned int adc_config;
76*4882a593Smuzhiyun int adbu;
77*4882a593Smuzhiyun int gain;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun switch (mask) {
80*4882a593Smuzhiyun case IIO_CHAN_INFO_HARDWAREGAIN:
81*4882a593Smuzhiyun /* get gain configuration */
82*4882a593Smuzhiyun adc_config = inb(priv->base + 11);
83*4882a593Smuzhiyun gain = adc_config & 0x3;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun *val = 1 << gain;
86*4882a593Smuzhiyun return IIO_VAL_INT;
87*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
88*4882a593Smuzhiyun if (chan->output) {
89*4882a593Smuzhiyun *val = priv->chan_out_states[chan->channel];
90*4882a593Smuzhiyun return IIO_VAL_INT;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /* select ADC channel */
94*4882a593Smuzhiyun outb(chan->channel | (chan->channel << 4), priv->base + 2);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* trigger ADC sample capture and wait for completion */
97*4882a593Smuzhiyun outb(0, priv->base);
98*4882a593Smuzhiyun while (inb(priv->base + 8) & BIT(7));
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun *val = inw(priv->base);
101*4882a593Smuzhiyun return IIO_VAL_INT;
102*4882a593Smuzhiyun case IIO_CHAN_INFO_OFFSET:
103*4882a593Smuzhiyun /* get ADC bipolar/unipolar configuration */
104*4882a593Smuzhiyun adc_config = inb(priv->base + 11);
105*4882a593Smuzhiyun adbu = !(adc_config & BIT(2));
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun *val = -32768 * adbu;
108*4882a593Smuzhiyun return IIO_VAL_INT;
109*4882a593Smuzhiyun case IIO_CHAN_INFO_SCALE:
110*4882a593Smuzhiyun /* get ADC bipolar/unipolar and gain configuration */
111*4882a593Smuzhiyun adc_config = inb(priv->base + 11);
112*4882a593Smuzhiyun adbu = !(adc_config & BIT(2));
113*4882a593Smuzhiyun gain = adc_config & 0x3;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun *val = 5;
116*4882a593Smuzhiyun *val2 = 15 - adbu + gain;
117*4882a593Smuzhiyun return IIO_VAL_FRACTIONAL_LOG2;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return -EINVAL;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
stx104_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)123*4882a593Smuzhiyun static int stx104_write_raw(struct iio_dev *indio_dev,
124*4882a593Smuzhiyun struct iio_chan_spec const *chan, int val, int val2, long mask)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun struct stx104_iio *const priv = iio_priv(indio_dev);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun switch (mask) {
129*4882a593Smuzhiyun case IIO_CHAN_INFO_HARDWAREGAIN:
130*4882a593Smuzhiyun /* Only four gain states (x1, x2, x4, x8) */
131*4882a593Smuzhiyun switch (val) {
132*4882a593Smuzhiyun case 1:
133*4882a593Smuzhiyun outb(0, priv->base + 11);
134*4882a593Smuzhiyun break;
135*4882a593Smuzhiyun case 2:
136*4882a593Smuzhiyun outb(1, priv->base + 11);
137*4882a593Smuzhiyun break;
138*4882a593Smuzhiyun case 4:
139*4882a593Smuzhiyun outb(2, priv->base + 11);
140*4882a593Smuzhiyun break;
141*4882a593Smuzhiyun case 8:
142*4882a593Smuzhiyun outb(3, priv->base + 11);
143*4882a593Smuzhiyun break;
144*4882a593Smuzhiyun default:
145*4882a593Smuzhiyun return -EINVAL;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun return 0;
149*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
150*4882a593Smuzhiyun if (chan->output) {
151*4882a593Smuzhiyun /* DAC can only accept up to a 16-bit value */
152*4882a593Smuzhiyun if ((unsigned int)val > 65535)
153*4882a593Smuzhiyun return -EINVAL;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun priv->chan_out_states[chan->channel] = val;
156*4882a593Smuzhiyun outw(val, priv->base + 4 + 2 * chan->channel);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun return 0;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun return -EINVAL;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun return -EINVAL;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun static const struct iio_info stx104_info = {
167*4882a593Smuzhiyun .read_raw = stx104_read_raw,
168*4882a593Smuzhiyun .write_raw = stx104_write_raw
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* single-ended input channels configuration */
172*4882a593Smuzhiyun static const struct iio_chan_spec stx104_channels_sing[] = {
173*4882a593Smuzhiyun STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
174*4882a593Smuzhiyun STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0),
175*4882a593Smuzhiyun STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0),
176*4882a593Smuzhiyun STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0),
177*4882a593Smuzhiyun STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0),
178*4882a593Smuzhiyun STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0),
179*4882a593Smuzhiyun STX104_IN_CHAN(15, 0)
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun /* differential input channels configuration */
182*4882a593Smuzhiyun static const struct iio_chan_spec stx104_channels_diff[] = {
183*4882a593Smuzhiyun STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
184*4882a593Smuzhiyun STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1),
185*4882a593Smuzhiyun STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1),
186*4882a593Smuzhiyun STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun
stx104_gpio_get_direction(struct gpio_chip * chip,unsigned int offset)189*4882a593Smuzhiyun static int stx104_gpio_get_direction(struct gpio_chip *chip,
190*4882a593Smuzhiyun unsigned int offset)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun /* GPIO 0-3 are input only, while the rest are output only */
193*4882a593Smuzhiyun if (offset < 4)
194*4882a593Smuzhiyun return 1;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun return 0;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
stx104_gpio_direction_input(struct gpio_chip * chip,unsigned int offset)199*4882a593Smuzhiyun static int stx104_gpio_direction_input(struct gpio_chip *chip,
200*4882a593Smuzhiyun unsigned int offset)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun if (offset >= 4)
203*4882a593Smuzhiyun return -EINVAL;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun return 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
stx104_gpio_direction_output(struct gpio_chip * chip,unsigned int offset,int value)208*4882a593Smuzhiyun static int stx104_gpio_direction_output(struct gpio_chip *chip,
209*4882a593Smuzhiyun unsigned int offset, int value)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun if (offset < 4)
212*4882a593Smuzhiyun return -EINVAL;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun chip->set(chip, offset, value);
215*4882a593Smuzhiyun return 0;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
stx104_gpio_get(struct gpio_chip * chip,unsigned int offset)218*4882a593Smuzhiyun static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (offset >= 4)
223*4882a593Smuzhiyun return -EINVAL;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun return !!(inb(stx104gpio->base) & BIT(offset));
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
stx104_gpio_get_multiple(struct gpio_chip * chip,unsigned long * mask,unsigned long * bits)228*4882a593Smuzhiyun static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
229*4882a593Smuzhiyun unsigned long *bits)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun *bits = inb(stx104gpio->base);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun return 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
stx104_gpio_set(struct gpio_chip * chip,unsigned int offset,int value)238*4882a593Smuzhiyun static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
239*4882a593Smuzhiyun int value)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
242*4882a593Smuzhiyun const unsigned int mask = BIT(offset) >> 4;
243*4882a593Smuzhiyun unsigned long flags;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun if (offset < 4)
246*4882a593Smuzhiyun return;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun spin_lock_irqsave(&stx104gpio->lock, flags);
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun if (value)
251*4882a593Smuzhiyun stx104gpio->out_state |= mask;
252*4882a593Smuzhiyun else
253*4882a593Smuzhiyun stx104gpio->out_state &= ~mask;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun outb(stx104gpio->out_state, stx104gpio->base);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun spin_unlock_irqrestore(&stx104gpio->lock, flags);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun #define STX104_NGPIO 8
261*4882a593Smuzhiyun static const char *stx104_names[STX104_NGPIO] = {
262*4882a593Smuzhiyun "DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"
263*4882a593Smuzhiyun };
264*4882a593Smuzhiyun
stx104_gpio_set_multiple(struct gpio_chip * chip,unsigned long * mask,unsigned long * bits)265*4882a593Smuzhiyun static void stx104_gpio_set_multiple(struct gpio_chip *chip,
266*4882a593Smuzhiyun unsigned long *mask, unsigned long *bits)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
269*4882a593Smuzhiyun unsigned long flags;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* verify masked GPIO are output */
272*4882a593Smuzhiyun if (!(*mask & 0xF0))
273*4882a593Smuzhiyun return;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun *mask >>= 4;
276*4882a593Smuzhiyun *bits >>= 4;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun spin_lock_irqsave(&stx104gpio->lock, flags);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun stx104gpio->out_state &= ~*mask;
281*4882a593Smuzhiyun stx104gpio->out_state |= *mask & *bits;
282*4882a593Smuzhiyun outb(stx104gpio->out_state, stx104gpio->base);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun spin_unlock_irqrestore(&stx104gpio->lock, flags);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
stx104_probe(struct device * dev,unsigned int id)287*4882a593Smuzhiyun static int stx104_probe(struct device *dev, unsigned int id)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun struct iio_dev *indio_dev;
290*4882a593Smuzhiyun struct stx104_iio *priv;
291*4882a593Smuzhiyun struct stx104_gpio *stx104gpio;
292*4882a593Smuzhiyun int err;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
295*4882a593Smuzhiyun if (!indio_dev)
296*4882a593Smuzhiyun return -ENOMEM;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL);
299*4882a593Smuzhiyun if (!stx104gpio)
300*4882a593Smuzhiyun return -ENOMEM;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (!devm_request_region(dev, base[id], STX104_EXTENT,
303*4882a593Smuzhiyun dev_name(dev))) {
304*4882a593Smuzhiyun dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
305*4882a593Smuzhiyun base[id], base[id] + STX104_EXTENT);
306*4882a593Smuzhiyun return -EBUSY;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun indio_dev->info = &stx104_info;
310*4882a593Smuzhiyun indio_dev->modes = INDIO_DIRECT_MODE;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun /* determine if differential inputs */
313*4882a593Smuzhiyun if (inb(base[id] + 8) & BIT(5)) {
314*4882a593Smuzhiyun indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff);
315*4882a593Smuzhiyun indio_dev->channels = stx104_channels_diff;
316*4882a593Smuzhiyun } else {
317*4882a593Smuzhiyun indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing);
318*4882a593Smuzhiyun indio_dev->channels = stx104_channels_sing;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun indio_dev->name = dev_name(dev);
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun priv = iio_priv(indio_dev);
324*4882a593Smuzhiyun priv->base = base[id];
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /* configure device for software trigger operation */
327*4882a593Smuzhiyun outb(0, base[id] + 9);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun /* initialize gain setting to x1 */
330*4882a593Smuzhiyun outb(0, base[id] + 11);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun /* initialize DAC output to 0V */
333*4882a593Smuzhiyun outw(0, base[id] + 4);
334*4882a593Smuzhiyun outw(0, base[id] + 6);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun stx104gpio->chip.label = dev_name(dev);
337*4882a593Smuzhiyun stx104gpio->chip.parent = dev;
338*4882a593Smuzhiyun stx104gpio->chip.owner = THIS_MODULE;
339*4882a593Smuzhiyun stx104gpio->chip.base = -1;
340*4882a593Smuzhiyun stx104gpio->chip.ngpio = STX104_NGPIO;
341*4882a593Smuzhiyun stx104gpio->chip.names = stx104_names;
342*4882a593Smuzhiyun stx104gpio->chip.get_direction = stx104_gpio_get_direction;
343*4882a593Smuzhiyun stx104gpio->chip.direction_input = stx104_gpio_direction_input;
344*4882a593Smuzhiyun stx104gpio->chip.direction_output = stx104_gpio_direction_output;
345*4882a593Smuzhiyun stx104gpio->chip.get = stx104_gpio_get;
346*4882a593Smuzhiyun stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
347*4882a593Smuzhiyun stx104gpio->chip.set = stx104_gpio_set;
348*4882a593Smuzhiyun stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
349*4882a593Smuzhiyun stx104gpio->base = base[id] + 3;
350*4882a593Smuzhiyun stx104gpio->out_state = 0x0;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun spin_lock_init(&stx104gpio->lock);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun err = devm_gpiochip_add_data(dev, &stx104gpio->chip, stx104gpio);
355*4882a593Smuzhiyun if (err) {
356*4882a593Smuzhiyun dev_err(dev, "GPIO registering failed (%d)\n", err);
357*4882a593Smuzhiyun return err;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun return devm_iio_device_register(dev, indio_dev);
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun static struct isa_driver stx104_driver = {
364*4882a593Smuzhiyun .probe = stx104_probe,
365*4882a593Smuzhiyun .driver = {
366*4882a593Smuzhiyun .name = "stx104"
367*4882a593Smuzhiyun },
368*4882a593Smuzhiyun };
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun module_isa_driver(stx104_driver, num_stx104);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
373*4882a593Smuzhiyun MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
374*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
375