root/drivers/staging/comedi/drivers/c6xdigio.c

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

DEFINITIONS

This source file includes following definitions.
  1. c6xdigio_chk_status
  2. c6xdigio_write_data
  3. c6xdigio_get_encoder_bits
  4. c6xdigio_pwm_write
  5. c6xdigio_encoder_read
  6. c6xdigio_pwm_insn_write
  7. c6xdigio_pwm_insn_read
  8. c6xdigio_encoder_insn_read
  9. c6xdigio_init
  10. c6xdigio_attach
  11. c6xdigio_detach

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * c6xdigio.c
   4  * Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card.
   5  * http://web.archive.org/web/%2A/http://robot0.ge.uiuc.edu/~spong/mecha/
   6  *
   7  * COMEDI - Linux Control and Measurement Device Interface
   8  * Copyright (C) 1999 Dan Block
   9  */
  10 
  11 /*
  12  * Driver: c6xdigio
  13  * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card
  14  * Author: Dan Block
  15  * Status: unknown
  16  * Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio)
  17  * Updated: Sun Nov 20 20:18:34 EST 2005
  18  *
  19  * Configuration Options:
  20  *      [0] - base address
  21  */
  22 
  23 #include <linux/kernel.h>
  24 #include <linux/module.h>
  25 #include <linux/sched.h>
  26 #include <linux/mm.h>
  27 #include <linux/errno.h>
  28 #include <linux/interrupt.h>
  29 #include <linux/timex.h>
  30 #include <linux/timer.h>
  31 #include <linux/io.h>
  32 #include <linux/pnp.h>
  33 
  34 #include "../comedidev.h"
  35 
  36 /*
  37  * Register I/O map
  38  */
  39 #define C6XDIGIO_DATA_REG       0x00
  40 #define C6XDIGIO_DATA_CHAN(x)   (((x) + 1) << 4)
  41 #define C6XDIGIO_DATA_PWM       BIT(5)
  42 #define C6XDIGIO_DATA_ENCODER   BIT(6)
  43 #define C6XDIGIO_STATUS_REG     0x01
  44 #define C6XDIGIO_CTRL_REG       0x02
  45 
  46 #define C6XDIGIO_TIME_OUT 20
  47 
  48 static int c6xdigio_chk_status(struct comedi_device *dev, unsigned long context)
  49 {
  50         unsigned int status;
  51         int timeout = 0;
  52 
  53         do {
  54                 status = inb(dev->iobase + C6XDIGIO_STATUS_REG);
  55                 if ((status & 0x80) != context)
  56                         return 0;
  57                 timeout++;
  58         } while  (timeout < C6XDIGIO_TIME_OUT);
  59 
  60         return -EBUSY;
  61 }
  62 
  63 static int c6xdigio_write_data(struct comedi_device *dev,
  64                                unsigned int val, unsigned int status)
  65 {
  66         outb_p(val, dev->iobase + C6XDIGIO_DATA_REG);
  67         return c6xdigio_chk_status(dev, status);
  68 }
  69 
  70 static int c6xdigio_get_encoder_bits(struct comedi_device *dev,
  71                                      unsigned int *bits,
  72                                      unsigned int cmd,
  73                                      unsigned int status)
  74 {
  75         unsigned int val;
  76 
  77         val = inb(dev->iobase + C6XDIGIO_STATUS_REG);
  78         val >>= 3;
  79         val &= 0x07;
  80 
  81         *bits = val;
  82 
  83         return c6xdigio_write_data(dev, cmd, status);
  84 }
  85 
  86 static void c6xdigio_pwm_write(struct comedi_device *dev,
  87                                unsigned int chan, unsigned int val)
  88 {
  89         unsigned int cmd = C6XDIGIO_DATA_PWM | C6XDIGIO_DATA_CHAN(chan);
  90         unsigned int bits;
  91 
  92         if (val > 498)
  93                 val = 498;
  94         if (val < 2)
  95                 val = 2;
  96 
  97         bits = (val >> 0) & 0x03;
  98         c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00);
  99         bits = (val >> 2) & 0x03;
 100         c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80);
 101         bits = (val >> 4) & 0x03;
 102         c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00);
 103         bits = (val >> 6) & 0x03;
 104         c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80);
 105         bits = (val >> 8) & 0x03;
 106         c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00);
 107 
 108         c6xdigio_write_data(dev, 0x00, 0x80);
 109 }
 110 
 111 static int c6xdigio_encoder_read(struct comedi_device *dev,
 112                                  unsigned int chan)
 113 {
 114         unsigned int cmd = C6XDIGIO_DATA_ENCODER | C6XDIGIO_DATA_CHAN(chan);
 115         unsigned int val = 0;
 116         unsigned int bits;
 117 
 118         c6xdigio_write_data(dev, cmd, 0x00);
 119 
 120         c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
 121         val |= (bits << 0);
 122 
 123         c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
 124         val |= (bits << 3);
 125 
 126         c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
 127         val |= (bits << 6);
 128 
 129         c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
 130         val |= (bits << 9);
 131 
 132         c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
 133         val |= (bits << 12);
 134 
 135         c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
 136         val |= (bits << 15);
 137 
 138         c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
 139         val |= (bits << 18);
 140 
 141         c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
 142         val |= (bits << 21);
 143 
 144         c6xdigio_write_data(dev, 0x00, 0x80);
 145 
 146         return val;
 147 }
 148 
 149 static int c6xdigio_pwm_insn_write(struct comedi_device *dev,
 150                                    struct comedi_subdevice *s,
 151                                    struct comedi_insn *insn,
 152                                    unsigned int *data)
 153 {
 154         unsigned int chan = CR_CHAN(insn->chanspec);
 155         unsigned int val = (s->state >> (16 * chan)) & 0xffff;
 156         int i;
 157 
 158         for (i = 0; i < insn->n; i++) {
 159                 val = data[i];
 160                 c6xdigio_pwm_write(dev, chan, val);
 161         }
 162 
 163         /*
 164          * There are only 2 PWM channels and they have a maxdata of 500.
 165          * Instead of allocating private data to save the values in for
 166          * readback this driver just packs the values for the two channels
 167          * in the s->state.
 168          */
 169         s->state &= (0xffff << (16 * chan));
 170         s->state |= (val << (16 * chan));
 171 
 172         return insn->n;
 173 }
 174 
 175 static int c6xdigio_pwm_insn_read(struct comedi_device *dev,
 176                                   struct comedi_subdevice *s,
 177                                   struct comedi_insn *insn,
 178                                   unsigned int *data)
 179 {
 180         unsigned int chan = CR_CHAN(insn->chanspec);
 181         unsigned int val;
 182         int i;
 183 
 184         val = (s->state >> (16 * chan)) & 0xffff;
 185 
 186         for (i = 0; i < insn->n; i++)
 187                 data[i] = val;
 188 
 189         return insn->n;
 190 }
 191 
 192 static int c6xdigio_encoder_insn_read(struct comedi_device *dev,
 193                                       struct comedi_subdevice *s,
 194                                       struct comedi_insn *insn,
 195                                       unsigned int *data)
 196 {
 197         unsigned int chan = CR_CHAN(insn->chanspec);
 198         unsigned int val;
 199         int i;
 200 
 201         for (i = 0; i < insn->n; i++) {
 202                 val = c6xdigio_encoder_read(dev, chan);
 203 
 204                 /* munge two's complement value to offset binary */
 205                 data[i] = comedi_offset_munge(s, val);
 206         }
 207 
 208         return insn->n;
 209 }
 210 
 211 static void c6xdigio_init(struct comedi_device *dev)
 212 {
 213         /* Initialize the PWM */
 214         c6xdigio_write_data(dev, 0x70, 0x00);
 215         c6xdigio_write_data(dev, 0x74, 0x80);
 216         c6xdigio_write_data(dev, 0x70, 0x00);
 217         c6xdigio_write_data(dev, 0x00, 0x80);
 218 
 219         /* Reset the encoders */
 220         c6xdigio_write_data(dev, 0x68, 0x00);
 221         c6xdigio_write_data(dev, 0x6c, 0x80);
 222         c6xdigio_write_data(dev, 0x68, 0x00);
 223         c6xdigio_write_data(dev, 0x00, 0x80);
 224 }
 225 
 226 static const struct pnp_device_id c6xdigio_pnp_tbl[] = {
 227         /* Standard LPT Printer Port */
 228         {.id = "PNP0400", .driver_data = 0},
 229         /* ECP Printer Port */
 230         {.id = "PNP0401", .driver_data = 0},
 231         {}
 232 };
 233 
 234 static struct pnp_driver c6xdigio_pnp_driver = {
 235         .name = "c6xdigio",
 236         .id_table = c6xdigio_pnp_tbl,
 237 };
 238 
 239 static int c6xdigio_attach(struct comedi_device *dev,
 240                            struct comedi_devconfig *it)
 241 {
 242         struct comedi_subdevice *s;
 243         int ret;
 244 
 245         ret = comedi_request_region(dev, it->options[0], 0x03);
 246         if (ret)
 247                 return ret;
 248 
 249         ret = comedi_alloc_subdevices(dev, 2);
 250         if (ret)
 251                 return ret;
 252 
 253         /*  Make sure that PnP ports get activated */
 254         pnp_register_driver(&c6xdigio_pnp_driver);
 255 
 256         s = &dev->subdevices[0];
 257         /* pwm output subdevice */
 258         s->type         = COMEDI_SUBD_PWM;
 259         s->subdev_flags = SDF_WRITABLE;
 260         s->n_chan       = 2;
 261         s->maxdata      = 500;
 262         s->range_table  = &range_unknown;
 263         s->insn_write   = c6xdigio_pwm_insn_write;
 264         s->insn_read    = c6xdigio_pwm_insn_read;
 265 
 266         s = &dev->subdevices[1];
 267         /* encoder (counter) subdevice */
 268         s->type         = COMEDI_SUBD_COUNTER;
 269         s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
 270         s->n_chan       = 2;
 271         s->maxdata      = 0xffffff;
 272         s->range_table  = &range_unknown;
 273         s->insn_read    = c6xdigio_encoder_insn_read;
 274 
 275         /*  I will call this init anyway but more than likely the DSP board */
 276         /*  will not be connected when device driver is loaded. */
 277         c6xdigio_init(dev);
 278 
 279         return 0;
 280 }
 281 
 282 static void c6xdigio_detach(struct comedi_device *dev)
 283 {
 284         comedi_legacy_detach(dev);
 285         pnp_unregister_driver(&c6xdigio_pnp_driver);
 286 }
 287 
 288 static struct comedi_driver c6xdigio_driver = {
 289         .driver_name    = "c6xdigio",
 290         .module         = THIS_MODULE,
 291         .attach         = c6xdigio_attach,
 292         .detach         = c6xdigio_detach,
 293 };
 294 module_comedi_driver(c6xdigio_driver);
 295 
 296 MODULE_AUTHOR("Comedi http://www.comedi.org");
 297 MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card");
 298 MODULE_LICENSE("GPL");

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