linux/drivers/iio/adc/stx104.c
<<
>>
Prefs
   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");
 375
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.