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