Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
adv_pci1723.c
Go to the documentation of this file.
1 /*******************************************************************************
2  comedi/drivers/pci1723.c
3 
4  COMEDI - Linux Control and Measurement Device Interface
5  Copyright (C) 2000 David A. Schleef <[email protected]>
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 *******************************************************************************/
22 /*
23 Driver: adv_pci1723
24 Description: Advantech PCI-1723
25 Author: yonggang <[email protected]>, Ian Abbott <[email protected]>
26 Devices: [Advantech] PCI-1723 (adv_pci1723)
27 Updated: Mon, 14 Apr 2008 15:12:56 +0100
28 Status: works
29 
30 Configuration Options:
31  [0] - PCI bus of device (optional)
32  [1] - PCI slot of device (optional)
33 
34  If bus/slot is not specified, the first supported
35  PCI device found will be used.
36 
37 Subdevice 0 is 8-channel AO, 16-bit, range +/- 10 V.
38 
39 Subdevice 1 is 16-channel DIO. The channels are configurable as input or
40 output in 2 groups (0 to 7, 8 to 15). Configuring any channel implicitly
41 configures all channels in the same group.
42 
43 TODO:
44 
45 1. Add the two milliamp ranges to the AO subdevice (0 to 20 mA, 4 to 20 mA).
46 2. Read the initial ranges and values of the AO subdevice at start-up instead
47  of reinitializing them.
48 3. Implement calibration.
49 */
50 
51 #include "../comedidev.h"
52 
53 #define PCI_VENDOR_ID_ADVANTECH 0x13fe /* Advantech PCI vendor ID */
54 
55 /* all the registers for the pci1723 board */
56 #define PCI1723_DA(N) ((N)<<1) /* W: D/A register N (0 to 7) */
57 
58 #define PCI1723_SYN_SET 0x12 /* synchronized set register */
59 #define PCI1723_ALL_CHNNELE_SYN_STROBE 0x12
60  /* synchronized status register */
61 
62 #define PCI1723_RANGE_CALIBRATION_MODE 0x14
63  /* range and calibration mode */
64 #define PCI1723_RANGE_CALIBRATION_STATUS 0x14
65  /* range and calibration status */
66 
67 #define PCI1723_CONTROL_CMD_CALIBRATION_FUN 0x16
68  /*
69  * SADC control command for
70  * calibration function
71  */
72 #define PCI1723_STATUS_CMD_CALIBRATION_FUN 0x16
73  /*
74  * SADC control status for
75  * calibration function
76  */
77 
78 #define PCI1723_CALIBRATION_PARA_STROBE 0x18
79  /* Calibration parameter strobe */
80 
81 #define PCI1723_DIGITAL_IO_PORT_SET 0x1A /* Digital I/O port setting */
82 #define PCI1723_DIGITAL_IO_PORT_MODE 0x1A /* Digital I/O port mode */
83 
84 #define PCI1723_WRITE_DIGITAL_OUTPUT_CMD 0x1C
85  /* Write digital output command */
86 #define PCI1723_READ_DIGITAL_INPUT_DATA 0x1C /* Read digital input data */
87 
88 #define PCI1723_WRITE_CAL_CMD 0x1E /* Write calibration command */
89 #define PCI1723_READ_CAL_STATUS 0x1E /* Read calibration status */
90 
91 #define PCI1723_SYN_STROBE 0x20 /* Synchronized strobe */
92 
93 #define PCI1723_RESET_ALL_CHN_STROBE 0x22
94  /* Reset all D/A channels strobe */
95 
96 #define PCI1723_RESET_CAL_CONTROL_STROBE 0x24
97  /*
98  * Reset the calibration
99  * controller strobe
100  */
101 
102 #define PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE 0x26
103  /*
104  * Change D/A channels output
105  * type strobe
106  */
107 
108 #define PCI1723_SELECT_CALIBRATION 0x28 /* Select the calibration Ref_V */
109 
111  unsigned char da_range[8]; /* D/A output range for each channel */
112  short ao_data[8]; /* data output buffer */
113 };
114 
115 /*
116  * The pci1723 card reset;
117  */
118 static int pci1723_reset(struct comedi_device *dev)
119 {
120  struct pci1723_private *devpriv = dev->private;
121  int i;
122 
123  outw(0x01, dev->iobase + PCI1723_SYN_SET);
124  /* set synchronous output mode */
125 
126  for (i = 0; i < 8; i++) {
127  /* set all outputs to 0V */
128  devpriv->ao_data[i] = 0x8000;
129  outw(devpriv->ao_data[i], dev->iobase + PCI1723_DA(i));
130  /* set all ranges to +/- 10V */
131  devpriv->da_range[i] = 0;
132  outw(((devpriv->da_range[i] << 4) | i),
134  }
135 
137  /* update ranges */
138  outw(0, dev->iobase + PCI1723_SYN_STROBE); /* update outputs */
139 
140  /* set asynchronous output mode */
141  outw(0, dev->iobase + PCI1723_SYN_SET);
142 
143  return 0;
144 }
145 
146 static int pci1723_insn_read_ao(struct comedi_device *dev,
147  struct comedi_subdevice *s,
148  struct comedi_insn *insn, unsigned int *data)
149 {
150  struct pci1723_private *devpriv = dev->private;
151  int n, chan;
152 
153  chan = CR_CHAN(insn->chanspec);
154  for (n = 0; n < insn->n; n++)
155  data[n] = devpriv->ao_data[chan];
156 
157  return n;
158 }
159 
160 /*
161  analog data output;
162 */
163 static int pci1723_ao_write_winsn(struct comedi_device *dev,
164  struct comedi_subdevice *s,
165  struct comedi_insn *insn, unsigned int *data)
166 {
167  struct pci1723_private *devpriv = dev->private;
168  int n, chan;
169  chan = CR_CHAN(insn->chanspec);
170 
171  for (n = 0; n < insn->n; n++) {
172 
173  devpriv->ao_data[chan] = data[n];
174  outw(data[n], dev->iobase + PCI1723_DA(chan));
175  }
176 
177  return n;
178 }
179 
180 /*
181  digital i/o config/query
182 */
183 static int pci1723_dio_insn_config(struct comedi_device *dev,
184  struct comedi_subdevice *s,
185  struct comedi_insn *insn, unsigned int *data)
186 {
187  unsigned int mask;
188  unsigned int bits;
189  unsigned short dio_mode;
190 
191  mask = 1 << CR_CHAN(insn->chanspec);
192  if (mask & 0x00FF)
193  bits = 0x00FF;
194  else
195  bits = 0xFF00;
196 
197  switch (data[0]) {
199  s->io_bits &= ~bits;
200  break;
202  s->io_bits |= bits;
203  break;
205  data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
206  return insn->n;
207  default:
208  return -EINVAL;
209  }
210 
211  /* update hardware DIO mode */
212  dio_mode = 0x0000; /* low byte output, high byte output */
213  if ((s->io_bits & 0x00FF) == 0)
214  dio_mode |= 0x0001; /* low byte input */
215  if ((s->io_bits & 0xFF00) == 0)
216  dio_mode |= 0x0002; /* high byte input */
217  outw(dio_mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET);
218  return 1;
219 }
220 
221 /*
222  digital i/o bits read/write
223 */
224 static int pci1723_dio_insn_bits(struct comedi_device *dev,
225  struct comedi_subdevice *s,
226  struct comedi_insn *insn, unsigned int *data)
227 {
228  if (data[0]) {
229  s->state &= ~data[0];
230  s->state |= (data[0] & data[1]);
232  }
233  data[1] = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA);
234  return insn->n;
235 }
236 
237 static int pci1723_attach_pci(struct comedi_device *dev,
238  struct pci_dev *pcidev)
239 {
240  struct pci1723_private *devpriv;
241  struct comedi_subdevice *s;
242  int ret;
243 
244  comedi_set_hw_dev(dev, &pcidev->dev);
245  dev->board_name = dev->driver->driver_name;
246 
247  ret = alloc_private(dev, sizeof(*devpriv));
248  if (ret < 0)
249  return ret;
250  devpriv = dev->private;
251 
252  ret = comedi_pci_enable(pcidev, dev->board_name);
253  if (ret)
254  return ret;
255  dev->iobase = pci_resource_start(pcidev, 2);
256 
257  ret = comedi_alloc_subdevices(dev, 2);
258  if (ret)
259  return ret;
260 
261  s = &dev->subdevices[0];
262  dev->write_subdev = s;
263  s->type = COMEDI_SUBD_AO;
265  s->n_chan = 8;
266  s->maxdata = 0xffff;
267  s->len_chanlist = 8;
269  s->insn_write = pci1723_ao_write_winsn;
270  s->insn_read = pci1723_insn_read_ao;
271 
272  s = &dev->subdevices[1];
273  s->type = COMEDI_SUBD_DIO;
275  s->n_chan = 16;
276  s->maxdata = 1;
277  s->len_chanlist = 16;
279  s->insn_config = pci1723_dio_insn_config;
280  s->insn_bits = pci1723_dio_insn_bits;
281 
282  /* read DIO config */
283  switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) & 0x03) {
284  case 0x00: /* low byte output, high byte output */
285  s->io_bits = 0xFFFF;
286  break;
287  case 0x01: /* low byte input, high byte output */
288  s->io_bits = 0xFF00;
289  break;
290  case 0x02: /* low byte output, high byte input */
291  s->io_bits = 0x00FF;
292  break;
293  case 0x03: /* low byte input, high byte input */
294  s->io_bits = 0x0000;
295  break;
296  }
297  /* read DIO port state */
299 
300  pci1723_reset(dev);
301 
302  dev_info(dev->class_dev, "%s attached\n", dev->board_name);
303 
304  return 0;
305 }
306 
307 static void pci1723_detach(struct comedi_device *dev)
308 {
309  struct pci_dev *pcidev = comedi_to_pci_dev(dev);
310 
311  if (pcidev) {
312  if (dev->iobase) {
313  pci1723_reset(dev);
314  comedi_pci_disable(pcidev);
315  }
316  }
317 }
318 
319 static struct comedi_driver adv_pci1723_driver = {
320  .driver_name = "adv_pci1723",
321  .module = THIS_MODULE,
322  .attach_pci = pci1723_attach_pci,
323  .detach = pci1723_detach,
324 };
325 
326 static int __devinit adv_pci1723_pci_probe(struct pci_dev *dev,
327  const struct pci_device_id *ent)
328 {
329  return comedi_pci_auto_config(dev, &adv_pci1723_driver);
330 }
331 
332 static void __devexit adv_pci1723_pci_remove(struct pci_dev *dev)
333 {
335 }
336 
337 static DEFINE_PCI_DEVICE_TABLE(adv_pci1723_pci_table) = {
338  { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) },
339  { 0 }
340 };
341 MODULE_DEVICE_TABLE(pci, adv_pci1723_pci_table);
342 
343 static struct pci_driver adv_pci1723_pci_driver = {
344  .name = "adv_pci1723",
345  .id_table = adv_pci1723_pci_table,
346  .probe = adv_pci1723_pci_probe,
347  .remove = __devexit_p(adv_pci1723_pci_remove),
348 };
349 module_comedi_pci_driver(adv_pci1723_driver, adv_pci1723_pci_driver);
350 
351 MODULE_AUTHOR("Comedi http://www.comedi.org");
352 MODULE_DESCRIPTION("Comedi low-level driver");
353 MODULE_LICENSE("GPL");