root/drivers/iio/adc/stx104.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. stx104_read_raw
  2. stx104_write_raw
  3. stx104_gpio_get_direction
  4. stx104_gpio_direction_input
  5. stx104_gpio_direction_output
  6. stx104_gpio_get
  7. stx104_gpio_get_multiple
  8. stx104_gpio_set
  9. stx104_gpio_set_multiple
  10. stx104_probe

   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 
  42 static unsigned int base[max_num_isa_dev(STX104_EXTENT)];
  43 static unsigned int num_stx104;
  44 module_param_hw_array(base, uint, ioport, &num_stx104, 0);
  45 MODULE_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  */
  52 struct 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  */
  64 struct stx104_gpio {
  65         struct gpio_chip chip;
  66         spinlock_t lock;
  67         unsigned int base;
  68         unsigned int out_state;
  69 };
  70 
  71 static 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 
 123 static 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 
 166 static 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 */
 172 static 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 */
 182 static 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 
 189 static 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 
 199 static 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 
 208 static 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 
 218 static 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 
 228 static 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 
 238 static 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
 261 static const char *stx104_names[STX104_NGPIO] = {
 262         "DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"
 263 };
 264 
 265 static 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 
 287 static 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         indio_dev->dev.parent = dev;
 323 
 324         priv = iio_priv(indio_dev);
 325         priv->base = base[id];
 326 
 327         /* configure device for software trigger operation */
 328         outb(0, base[id] + 9);
 329 
 330         /* initialize gain setting to x1 */
 331         outb(0, base[id] + 11);
 332 
 333         /* initialize DAC output to 0V */
 334         outw(0, base[id] + 4);
 335         outw(0, base[id] + 6);
 336 
 337         stx104gpio->chip.label = dev_name(dev);
 338         stx104gpio->chip.parent = dev;
 339         stx104gpio->chip.owner = THIS_MODULE;
 340         stx104gpio->chip.base = -1;
 341         stx104gpio->chip.ngpio = STX104_NGPIO;
 342         stx104gpio->chip.names = stx104_names;
 343         stx104gpio->chip.get_direction = stx104_gpio_get_direction;
 344         stx104gpio->chip.direction_input = stx104_gpio_direction_input;
 345         stx104gpio->chip.direction_output = stx104_gpio_direction_output;
 346         stx104gpio->chip.get = stx104_gpio_get;
 347         stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
 348         stx104gpio->chip.set = stx104_gpio_set;
 349         stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
 350         stx104gpio->base = base[id] + 3;
 351         stx104gpio->out_state = 0x0;
 352 
 353         spin_lock_init(&stx104gpio->lock);
 354 
 355         err = devm_gpiochip_add_data(dev, &stx104gpio->chip, stx104gpio);
 356         if (err) {
 357                 dev_err(dev, "GPIO registering failed (%d)\n", err);
 358                 return err;
 359         }
 360 
 361         return devm_iio_device_register(dev, indio_dev);
 362 }
 363 
 364 static struct isa_driver stx104_driver = {
 365         .probe = stx104_probe,
 366         .driver = {
 367                 .name = "stx104"
 368         },
 369 };
 370 
 371 module_isa_driver(stx104_driver, num_stx104);
 372 
 373 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
 374 MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
 375 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */