1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * IIO driver for the Apex Embedded Systems STX104 |
4 | * Copyright (C) 2016 William Breathitt Gray |
5 | */ |
6 | #include <linux/bitfield.h> |
7 | #include <linux/bits.h> |
8 | #include <linux/device.h> |
9 | #include <linux/err.h> |
10 | #include <linux/gpio/regmap.h> |
11 | #include <linux/i8254.h> |
12 | #include <linux/iio/iio.h> |
13 | #include <linux/iio/types.h> |
14 | #include <linux/isa.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/limits.h> |
17 | #include <linux/module.h> |
18 | #include <linux/moduleparam.h> |
19 | #include <linux/mutex.h> |
20 | #include <linux/regmap.h> |
21 | #include <linux/types.h> |
22 | |
23 | #define STX104_OUT_CHAN(chan) { \ |
24 | .type = IIO_VOLTAGE, \ |
25 | .channel = chan, \ |
26 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
27 | .indexed = 1, \ |
28 | .output = 1 \ |
29 | } |
30 | #define STX104_IN_CHAN(chan, diff) { \ |
31 | .type = IIO_VOLTAGE, \ |
32 | .channel = chan, \ |
33 | .channel2 = chan, \ |
34 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ |
35 | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \ |
36 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
37 | .indexed = 1, \ |
38 | .differential = diff \ |
39 | } |
40 | |
41 | #define STX104_NUM_OUT_CHAN 2 |
42 | |
43 | #define STX104_EXTENT 16 |
44 | |
45 | static unsigned int base[max_num_isa_dev(STX104_EXTENT)]; |
46 | static unsigned int num_stx104; |
47 | module_param_hw_array(base, uint, ioport, &num_stx104, 0); |
48 | MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses" ); |
49 | |
50 | #define STX104_AIO_BASE 0x0 |
51 | #define STX104_SOFTWARE_STROBE STX104_AIO_BASE |
52 | #define STX104_ADC_DATA STX104_AIO_BASE |
53 | #define STX104_ADC_CHANNEL (STX104_AIO_BASE + 0x2) |
54 | #define STX104_DIO_REG (STX104_AIO_BASE + 0x3) |
55 | #define STX104_DAC_BASE (STX104_AIO_BASE + 0x4) |
56 | #define STX104_ADC_STATUS (STX104_AIO_BASE + 0x8) |
57 | #define STX104_ADC_CONTROL (STX104_AIO_BASE + 0x9) |
58 | #define STX104_ADC_CONFIGURATION (STX104_AIO_BASE + 0x11) |
59 | #define STX104_I8254_BASE (STX104_AIO_BASE + 0x12) |
60 | |
61 | #define STX104_AIO_DATA_STRIDE 2 |
62 | #define STX104_DAC_OFFSET(_channel) (STX104_DAC_BASE + STX104_AIO_DATA_STRIDE * (_channel)) |
63 | |
64 | /* ADC Channel */ |
65 | #define STX104_FC GENMASK(3, 0) |
66 | #define STX104_LC GENMASK(7, 4) |
67 | #define STX104_SINGLE_CHANNEL(_channel) \ |
68 | (u8_encode_bits(_channel, STX104_FC) | u8_encode_bits(_channel, STX104_LC)) |
69 | |
70 | /* ADC Status */ |
71 | #define STX104_SD BIT(5) |
72 | #define STX104_CNV BIT(7) |
73 | #define STX104_DIFFERENTIAL 1 |
74 | |
75 | /* ADC Control */ |
76 | #define STX104_ALSS GENMASK(1, 0) |
77 | #define STX104_SOFTWARE_TRIGGER u8_encode_bits(0x0, STX104_ALSS) |
78 | |
79 | /* ADC Configuration */ |
80 | #define STX104_GAIN GENMASK(1, 0) |
81 | #define STX104_ADBU BIT(2) |
82 | #define STX104_RBK GENMASK(7, 4) |
83 | #define STX104_BIPOLAR 0 |
84 | #define STX104_GAIN_X1 0 |
85 | #define STX104_GAIN_X2 1 |
86 | #define STX104_GAIN_X4 2 |
87 | #define STX104_GAIN_X8 3 |
88 | |
89 | /** |
90 | * struct stx104_iio - IIO device private data structure |
91 | * @lock: synchronization lock to prevent I/O race conditions |
92 | * @aio_data_map: Regmap for analog I/O data |
93 | * @aio_ctl_map: Regmap for analog I/O control |
94 | */ |
95 | struct stx104_iio { |
96 | struct mutex lock; |
97 | struct regmap *aio_data_map; |
98 | struct regmap *aio_ctl_map; |
99 | }; |
100 | |
101 | static const struct regmap_range aio_ctl_wr_ranges[] = { |
102 | regmap_reg_range(0x0, 0x0), regmap_reg_range(0x2, 0x2), regmap_reg_range(0x9, 0x9), |
103 | regmap_reg_range(0x11, 0x11), |
104 | }; |
105 | static const struct regmap_range aio_ctl_rd_ranges[] = { |
106 | regmap_reg_range(0x2, 0x2), regmap_reg_range(0x8, 0x9), regmap_reg_range(0x11, 0x11), |
107 | }; |
108 | static const struct regmap_range aio_ctl_volatile_ranges[] = { |
109 | regmap_reg_range(0x8, 0x8), |
110 | }; |
111 | static const struct regmap_access_table aio_ctl_wr_table = { |
112 | .yes_ranges = aio_ctl_wr_ranges, |
113 | .n_yes_ranges = ARRAY_SIZE(aio_ctl_wr_ranges), |
114 | }; |
115 | static const struct regmap_access_table aio_ctl_rd_table = { |
116 | .yes_ranges = aio_ctl_rd_ranges, |
117 | .n_yes_ranges = ARRAY_SIZE(aio_ctl_rd_ranges), |
118 | }; |
119 | static const struct regmap_access_table aio_ctl_volatile_table = { |
120 | .yes_ranges = aio_ctl_volatile_ranges, |
121 | .n_yes_ranges = ARRAY_SIZE(aio_ctl_volatile_ranges), |
122 | }; |
123 | |
124 | static const struct regmap_config aio_ctl_regmap_config = { |
125 | .name = "aio_ctl" , |
126 | .reg_bits = 8, |
127 | .reg_stride = 1, |
128 | .reg_base = STX104_AIO_BASE, |
129 | .val_bits = 8, |
130 | .io_port = true, |
131 | .wr_table = &aio_ctl_wr_table, |
132 | .rd_table = &aio_ctl_rd_table, |
133 | .volatile_table = &aio_ctl_volatile_table, |
134 | .cache_type = REGCACHE_FLAT, |
135 | }; |
136 | |
137 | static const struct regmap_range aio_data_wr_ranges[] = { |
138 | regmap_reg_range(0x4, 0x6), |
139 | }; |
140 | static const struct regmap_range aio_data_rd_ranges[] = { |
141 | regmap_reg_range(0x0, 0x0), |
142 | }; |
143 | static const struct regmap_access_table aio_data_wr_table = { |
144 | .yes_ranges = aio_data_wr_ranges, |
145 | .n_yes_ranges = ARRAY_SIZE(aio_data_wr_ranges), |
146 | }; |
147 | static const struct regmap_access_table aio_data_rd_table = { |
148 | .yes_ranges = aio_data_rd_ranges, |
149 | .n_yes_ranges = ARRAY_SIZE(aio_data_rd_ranges), |
150 | }; |
151 | |
152 | static const struct regmap_config aio_data_regmap_config = { |
153 | .name = "aio_data" , |
154 | .reg_bits = 16, |
155 | .reg_stride = STX104_AIO_DATA_STRIDE, |
156 | .reg_base = STX104_AIO_BASE, |
157 | .val_bits = 16, |
158 | .io_port = true, |
159 | .wr_table = &aio_data_wr_table, |
160 | .rd_table = &aio_data_rd_table, |
161 | .volatile_table = &aio_data_rd_table, |
162 | .cache_type = REGCACHE_FLAT, |
163 | }; |
164 | |
165 | static const struct regmap_config dio_regmap_config = { |
166 | .name = "dio" , |
167 | .reg_bits = 8, |
168 | .reg_stride = 1, |
169 | .reg_base = STX104_DIO_REG, |
170 | .val_bits = 8, |
171 | .io_port = true, |
172 | }; |
173 | |
174 | static const struct regmap_range pit_wr_ranges[] = { |
175 | regmap_reg_range(0x0, 0x3), |
176 | }; |
177 | static const struct regmap_range pit_rd_ranges[] = { |
178 | regmap_reg_range(0x0, 0x2), |
179 | }; |
180 | static const struct regmap_access_table pit_wr_table = { |
181 | .yes_ranges = pit_wr_ranges, |
182 | .n_yes_ranges = ARRAY_SIZE(pit_wr_ranges), |
183 | }; |
184 | static const struct regmap_access_table pit_rd_table = { |
185 | .yes_ranges = pit_rd_ranges, |
186 | .n_yes_ranges = ARRAY_SIZE(pit_rd_ranges), |
187 | }; |
188 | |
189 | static const struct regmap_config pit_regmap_config = { |
190 | .name = "i8254" , |
191 | .reg_bits = 8, |
192 | .reg_stride = 1, |
193 | .reg_base = STX104_I8254_BASE, |
194 | .val_bits = 8, |
195 | .io_port = true, |
196 | .wr_table = &pit_wr_table, |
197 | .rd_table = &pit_rd_table, |
198 | }; |
199 | |
200 | static int stx104_read_raw(struct iio_dev *indio_dev, |
201 | struct iio_chan_spec const *chan, int *val, int *val2, long mask) |
202 | { |
203 | struct stx104_iio *const priv = iio_priv(indio_dev); |
204 | int err; |
205 | unsigned int adc_config; |
206 | unsigned int value; |
207 | unsigned int adc_status; |
208 | |
209 | switch (mask) { |
210 | case IIO_CHAN_INFO_HARDWAREGAIN: |
211 | err = regmap_read(map: priv->aio_ctl_map, STX104_ADC_CONFIGURATION, val: &adc_config); |
212 | if (err) |
213 | return err; |
214 | |
215 | *val = BIT(u8_get_bits(adc_config, STX104_GAIN)); |
216 | return IIO_VAL_INT; |
217 | case IIO_CHAN_INFO_RAW: |
218 | if (chan->output) { |
219 | err = regmap_read(map: priv->aio_data_map, STX104_DAC_OFFSET(chan->channel), |
220 | val: &value); |
221 | if (err) |
222 | return err; |
223 | *val = value; |
224 | return IIO_VAL_INT; |
225 | } |
226 | |
227 | mutex_lock(&priv->lock); |
228 | |
229 | /* select ADC channel */ |
230 | err = regmap_write(map: priv->aio_ctl_map, STX104_ADC_CHANNEL, |
231 | STX104_SINGLE_CHANNEL(chan->channel)); |
232 | if (err) { |
233 | mutex_unlock(lock: &priv->lock); |
234 | return err; |
235 | } |
236 | |
237 | /* |
238 | * Trigger ADC sample capture by writing to the 8-bit Software Strobe Register and |
239 | * wait for completion; the conversion time range is 5 microseconds to 53.68 seconds |
240 | * in steps of 25 nanoseconds. The actual Analog Input Frame Timer time interval is |
241 | * calculated as: |
242 | * ai_time_frame_ns = ( AIFT + 1 ) * ( 25 nanoseconds ). |
243 | * Where 0 <= AIFT <= 2147483648. |
244 | */ |
245 | err = regmap_write(map: priv->aio_ctl_map, STX104_SOFTWARE_STROBE, val: 0); |
246 | if (err) { |
247 | mutex_unlock(lock: &priv->lock); |
248 | return err; |
249 | } |
250 | err = regmap_read_poll_timeout(priv->aio_ctl_map, STX104_ADC_STATUS, adc_status, |
251 | !u8_get_bits(adc_status, STX104_CNV), 0, 53687092); |
252 | if (err) { |
253 | mutex_unlock(lock: &priv->lock); |
254 | return err; |
255 | } |
256 | |
257 | err = regmap_read(map: priv->aio_data_map, STX104_ADC_DATA, val: &value); |
258 | if (err) { |
259 | mutex_unlock(lock: &priv->lock); |
260 | return err; |
261 | } |
262 | *val = value; |
263 | |
264 | mutex_unlock(lock: &priv->lock); |
265 | return IIO_VAL_INT; |
266 | case IIO_CHAN_INFO_OFFSET: |
267 | /* get ADC bipolar/unipolar configuration */ |
268 | err = regmap_read(map: priv->aio_ctl_map, STX104_ADC_CONFIGURATION, val: &adc_config); |
269 | if (err) |
270 | return err; |
271 | |
272 | *val = (u8_get_bits(v: adc_config, STX104_ADBU) == STX104_BIPOLAR) ? -32768 : 0; |
273 | return IIO_VAL_INT; |
274 | case IIO_CHAN_INFO_SCALE: |
275 | /* get ADC bipolar/unipolar and gain configuration */ |
276 | err = regmap_read(map: priv->aio_ctl_map, STX104_ADC_CONFIGURATION, val: &adc_config); |
277 | if (err) |
278 | return err; |
279 | |
280 | *val = 5; |
281 | *val2 = (u8_get_bits(v: adc_config, STX104_ADBU) == STX104_BIPOLAR) ? 14 : 15; |
282 | *val2 += u8_get_bits(v: adc_config, STX104_GAIN); |
283 | return IIO_VAL_FRACTIONAL_LOG2; |
284 | } |
285 | |
286 | return -EINVAL; |
287 | } |
288 | |
289 | static int stx104_write_raw(struct iio_dev *indio_dev, |
290 | struct iio_chan_spec const *chan, int val, int val2, long mask) |
291 | { |
292 | struct stx104_iio *const priv = iio_priv(indio_dev); |
293 | u8 gain; |
294 | |
295 | switch (mask) { |
296 | case IIO_CHAN_INFO_HARDWAREGAIN: |
297 | /* Only four gain states (x1, x2, x4, x8) */ |
298 | switch (val) { |
299 | case 1: |
300 | gain = STX104_GAIN_X1; |
301 | break; |
302 | case 2: |
303 | gain = STX104_GAIN_X2; |
304 | break; |
305 | case 4: |
306 | gain = STX104_GAIN_X4; |
307 | break; |
308 | case 8: |
309 | gain = STX104_GAIN_X8; |
310 | break; |
311 | default: |
312 | return -EINVAL; |
313 | } |
314 | |
315 | return regmap_write(map: priv->aio_ctl_map, STX104_ADC_CONFIGURATION, val: gain); |
316 | case IIO_CHAN_INFO_RAW: |
317 | if (!chan->output) |
318 | return -EINVAL; |
319 | |
320 | if (val < 0 || val > U16_MAX) |
321 | return -EINVAL; |
322 | |
323 | return regmap_write(map: priv->aio_data_map, STX104_DAC_OFFSET(chan->channel), val); |
324 | } |
325 | |
326 | return -EINVAL; |
327 | } |
328 | |
329 | static const struct iio_info stx104_info = { |
330 | .read_raw = stx104_read_raw, |
331 | .write_raw = stx104_write_raw |
332 | }; |
333 | |
334 | /* single-ended input channels configuration */ |
335 | static const struct iio_chan_spec stx104_channels_sing[] = { |
336 | STX104_OUT_CHAN(0), STX104_OUT_CHAN(1), |
337 | STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0), |
338 | STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0), |
339 | STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0), |
340 | STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0), |
341 | STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0), |
342 | STX104_IN_CHAN(15, 0) |
343 | }; |
344 | /* differential input channels configuration */ |
345 | static const struct iio_chan_spec stx104_channels_diff[] = { |
346 | STX104_OUT_CHAN(0), STX104_OUT_CHAN(1), |
347 | STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1), |
348 | STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1), |
349 | STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1) |
350 | }; |
351 | |
352 | static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base, |
353 | unsigned int offset, unsigned int *const reg, |
354 | unsigned int *const mask) |
355 | { |
356 | /* Output lines are located at same register bit offsets as input lines */ |
357 | if (offset >= 4) |
358 | offset -= 4; |
359 | |
360 | *reg = base; |
361 | *mask = BIT(offset); |
362 | |
363 | return 0; |
364 | } |
365 | |
366 | #define STX104_NGPIO 8 |
367 | static const char *stx104_names[STX104_NGPIO] = { |
368 | "DIN0" , "DIN1" , "DIN2" , "DIN3" , "DOUT0" , "DOUT1" , "DOUT2" , "DOUT3" |
369 | }; |
370 | |
371 | static int bank_select_i8254(struct regmap *map) |
372 | { |
373 | const u8 select_i8254[] = { 0x3, 0xB, 0xA }; |
374 | size_t i; |
375 | int err; |
376 | |
377 | for (i = 0; i < ARRAY_SIZE(select_i8254); i++) { |
378 | err = regmap_write_bits(map, STX104_ADC_CONFIGURATION, STX104_RBK, val: select_i8254[i]); |
379 | if (err) |
380 | return err; |
381 | } |
382 | |
383 | return 0; |
384 | } |
385 | |
386 | static int stx104_init_hw(struct stx104_iio *const priv) |
387 | { |
388 | int err; |
389 | |
390 | /* configure device for software trigger operation */ |
391 | err = regmap_write(map: priv->aio_ctl_map, STX104_ADC_CONTROL, STX104_SOFTWARE_TRIGGER); |
392 | if (err) |
393 | return err; |
394 | |
395 | /* initialize gain setting to x1 */ |
396 | err = regmap_write(map: priv->aio_ctl_map, STX104_ADC_CONFIGURATION, STX104_GAIN_X1); |
397 | if (err) |
398 | return err; |
399 | |
400 | /* initialize DAC outputs to 0V */ |
401 | err = regmap_write(map: priv->aio_data_map, STX104_DAC_BASE, val: 0); |
402 | if (err) |
403 | return err; |
404 | err = regmap_write(map: priv->aio_data_map, STX104_DAC_BASE + STX104_AIO_DATA_STRIDE, val: 0); |
405 | if (err) |
406 | return err; |
407 | |
408 | return bank_select_i8254(map: priv->aio_ctl_map); |
409 | } |
410 | |
411 | static int stx104_probe(struct device *dev, unsigned int id) |
412 | { |
413 | struct iio_dev *indio_dev; |
414 | struct stx104_iio *priv; |
415 | struct gpio_regmap_config gpio_config; |
416 | struct i8254_regmap_config pit_config; |
417 | void __iomem *stx104_base; |
418 | struct regmap *aio_ctl_map; |
419 | struct regmap *aio_data_map; |
420 | struct regmap *dio_map; |
421 | int err; |
422 | unsigned int adc_status; |
423 | |
424 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*priv)); |
425 | if (!indio_dev) |
426 | return -ENOMEM; |
427 | |
428 | if (!devm_request_region(dev, base[id], STX104_EXTENT, |
429 | dev_name(dev))) { |
430 | dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n" , |
431 | base[id], base[id] + STX104_EXTENT); |
432 | return -EBUSY; |
433 | } |
434 | |
435 | stx104_base = devm_ioport_map(dev, port: base[id], STX104_EXTENT); |
436 | if (!stx104_base) |
437 | return -ENOMEM; |
438 | |
439 | aio_ctl_map = devm_regmap_init_mmio(dev, stx104_base, &aio_ctl_regmap_config); |
440 | if (IS_ERR(ptr: aio_ctl_map)) |
441 | return dev_err_probe(dev, err: PTR_ERR(ptr: aio_ctl_map), |
442 | fmt: "Unable to initialize aio_ctl register map\n" ); |
443 | |
444 | aio_data_map = devm_regmap_init_mmio(dev, stx104_base, &aio_data_regmap_config); |
445 | if (IS_ERR(ptr: aio_data_map)) |
446 | return dev_err_probe(dev, err: PTR_ERR(ptr: aio_data_map), |
447 | fmt: "Unable to initialize aio_data register map\n" ); |
448 | |
449 | dio_map = devm_regmap_init_mmio(dev, stx104_base, &dio_regmap_config); |
450 | if (IS_ERR(ptr: dio_map)) |
451 | return dev_err_probe(dev, err: PTR_ERR(ptr: dio_map), |
452 | fmt: "Unable to initialize dio register map\n" ); |
453 | |
454 | pit_config.map = devm_regmap_init_mmio(dev, stx104_base, &pit_regmap_config); |
455 | if (IS_ERR(ptr: pit_config.map)) |
456 | return dev_err_probe(dev, err: PTR_ERR(ptr: pit_config.map), |
457 | fmt: "Unable to initialize i8254 register map\n" ); |
458 | |
459 | priv = iio_priv(indio_dev); |
460 | priv->aio_ctl_map = aio_ctl_map; |
461 | priv->aio_data_map = aio_data_map; |
462 | |
463 | indio_dev->info = &stx104_info; |
464 | indio_dev->modes = INDIO_DIRECT_MODE; |
465 | |
466 | err = regmap_read(map: aio_ctl_map, STX104_ADC_STATUS, val: &adc_status); |
467 | if (err) |
468 | return err; |
469 | |
470 | if (u8_get_bits(v: adc_status, STX104_SD) == STX104_DIFFERENTIAL) { |
471 | indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff); |
472 | indio_dev->channels = stx104_channels_diff; |
473 | } else { |
474 | indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing); |
475 | indio_dev->channels = stx104_channels_sing; |
476 | } |
477 | |
478 | indio_dev->name = dev_name(dev); |
479 | |
480 | mutex_init(&priv->lock); |
481 | |
482 | err = stx104_init_hw(priv); |
483 | if (err) |
484 | return err; |
485 | |
486 | err = devm_iio_device_register(dev, indio_dev); |
487 | if (err) |
488 | return err; |
489 | |
490 | gpio_config = (struct gpio_regmap_config) { |
491 | .parent = dev, |
492 | .regmap = dio_map, |
493 | .ngpio = STX104_NGPIO, |
494 | .names = stx104_names, |
495 | .reg_dat_base = GPIO_REGMAP_ADDR(STX104_DIO_REG), |
496 | .reg_set_base = GPIO_REGMAP_ADDR(STX104_DIO_REG), |
497 | .ngpio_per_reg = STX104_NGPIO, |
498 | .reg_mask_xlate = stx104_reg_mask_xlate, |
499 | .drvdata = dio_map, |
500 | }; |
501 | |
502 | err = PTR_ERR_OR_ZERO(ptr: devm_gpio_regmap_register(dev, config: &gpio_config)); |
503 | if (err) |
504 | return err; |
505 | |
506 | pit_config.parent = dev; |
507 | |
508 | return devm_i8254_regmap_register(dev, config: &pit_config); |
509 | } |
510 | |
511 | static struct isa_driver stx104_driver = { |
512 | .probe = stx104_probe, |
513 | .driver = { |
514 | .name = "stx104" |
515 | }, |
516 | }; |
517 | |
518 | module_isa_driver(stx104_driver, num_stx104); |
519 | |
520 | MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>" ); |
521 | MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver" ); |
522 | MODULE_LICENSE("GPL v2" ); |
523 | MODULE_IMPORT_NS(I8254); |
524 | |