Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[deliverable/linux.git] / drivers / staging / comedi / drivers / addi_apci_3120.c
CommitLineData
ce157f80 1#include <linux/module.h>
33782dd5
HS
2#include <linux/pci.h>
3
3d41c443
HS
4#include "../comedidev.h"
5#include "comedi_fc.h"
bf36f012 6#include "amcc_s5933.h"
3d41c443
HS
7
8#include "addi-data/addi_common.h"
3d41c443 9
bf6a1578 10#include "addi-data/hwdrv_apci3120.c"
bb6986f0 11
1df0e5b0
HS
12enum apci3120_boardid {
13 BOARD_APCI3120,
14 BOARD_APCI3001,
15};
16
20a22b70 17static const struct addi_board apci3120_boardtypes[] = {
1df0e5b0 18 [BOARD_APCI3120] = {
c0a053b8 19 .pc_DriverName = "apci3120",
c0a053b8
HS
20 .i_NbrAiChannel = 16,
21 .i_NbrAiChannelDiff = 8,
22 .i_AiChannelList = 16,
23 .i_NbrAoChannel = 8,
24 .i_AiMaxdata = 0xffff,
25 .i_AoMaxdata = 0x3fff,
c0a053b8
HS
26 .i_NbrDiChannel = 4,
27 .i_NbrDoChannel = 4,
28 .i_DoMaxdata = 0x0f,
805077b9 29 .interrupt = apci3120_interrupt,
1df0e5b0
HS
30 },
31 [BOARD_APCI3001] = {
973781a8 32 .pc_DriverName = "apci3001",
973781a8
HS
33 .i_NbrAiChannel = 16,
34 .i_NbrAiChannelDiff = 8,
35 .i_AiChannelList = 16,
36 .i_AiMaxdata = 0xfff,
973781a8
HS
37 .i_NbrDiChannel = 4,
38 .i_NbrDoChannel = 4,
39 .i_DoMaxdata = 0x0f,
805077b9 40 .interrupt = apci3120_interrupt,
c0a053b8
HS
41 },
42};
43
bb6986f0
HS
44static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
45{
46 struct comedi_device *dev = d;
db2d623b 47 const struct addi_board *this_board = dev->board_ptr;
bb6986f0
HS
48
49 this_board->interrupt(irq, d);
50 return IRQ_RETVAL(1);
51}
52
a690b7e5 53static int apci3120_auto_attach(struct comedi_device *dev,
1df0e5b0 54 unsigned long context)
bb6986f0 55{
891e62c3 56 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1df0e5b0 57 const struct addi_board *this_board = NULL;
bb6986f0
HS
58 struct addi_private *devpriv;
59 struct comedi_subdevice *s;
9c97e588 60 int ret, order, i;
bb6986f0 61
1df0e5b0
HS
62 if (context < ARRAY_SIZE(apci3120_boardtypes))
63 this_board = &apci3120_boardtypes[context];
bb6986f0
HS
64 if (!this_board)
65 return -ENODEV;
66 dev->board_ptr = this_board;
67 dev->board_name = this_board->pc_DriverName;
68
0bdab509 69 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
bb6986f0
HS
70 if (!devpriv)
71 return -ENOMEM;
bb6986f0 72
818f569f 73 ret = comedi_pci_enable(dev);
bb6986f0
HS
74 if (ret)
75 return ret;
4fbe36f2 76 pci_set_master(pcidev);
bb6986f0 77
65fe75a6 78 dev->iobase = pci_resource_start(pcidev, 1);
887f706e
HS
79 devpriv->iobase = dev->iobase;
80 devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0);
81 devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2);
bb6986f0
HS
82 devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3);
83
bb6986f0
HS
84 if (pcidev->irq > 0) {
85 ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED,
86 dev->board_name, dev);
87 if (ret == 0)
88 dev->irq = pcidev->irq;
89 }
90
4fbe36f2 91 /* Allocate DMA buffers */
4fbe36f2 92 for (i = 0; i < 2; i++) {
9c97e588 93 for (order = 2; order >= 0; order--) {
4fbe36f2 94 devpriv->ul_DmaBufferVirtual[i] =
fbfd9c8a
IA
95 dma_alloc_coherent(dev->hw_dev, PAGE_SIZE << order,
96 &devpriv->ul_DmaBufferHw[i],
97 GFP_KERNEL);
4fbe36f2
HS
98
99 if (devpriv->ul_DmaBufferVirtual[i])
100 break;
101 }
df567feb
IA
102 if (!devpriv->ul_DmaBufferVirtual[i])
103 break;
9c97e588 104 devpriv->ui_DmaBufferSize[i] = PAGE_SIZE << order;
bb6986f0 105 }
062fdcad
IA
106 if (devpriv->ul_DmaBufferVirtual[0])
107 devpriv->us_UseDma = 1;
4fbe36f2
HS
108
109 if (devpriv->ul_DmaBufferVirtual[1])
110 devpriv->b_DmaDoubleBuffer = 1;
bb6986f0 111
aea9c4e2 112 ret = comedi_alloc_subdevices(dev, 5);
bb6986f0
HS
113 if (ret)
114 return ret;
115
116 /* Allocate and Initialise AI Subdevice Structures */
117 s = &dev->subdevices[0];
50231a91
HS
118 dev->read_subdev = s;
119 s->type = COMEDI_SUBD_AI;
120 s->subdev_flags =
121 SDF_READABLE | SDF_COMMON | SDF_GROUND
122 | SDF_DIFF;
301b1ffc 123 if (this_board->i_NbrAiChannel)
50231a91 124 s->n_chan = this_board->i_NbrAiChannel;
301b1ffc 125 else
50231a91 126 s->n_chan = this_board->i_NbrAiChannelDiff;
50231a91
HS
127 s->maxdata = this_board->i_AiMaxdata;
128 s->len_chanlist = this_board->i_AiChannelList;
1ba296b9 129 s->range_table = &range_apci3120_ai;
50231a91 130
805077b9
FA
131 s->insn_config = apci3120_ai_insn_config;
132 s->insn_read = apci3120_ai_insn_read;
133 s->do_cmdtest = apci3120_ai_cmdtest;
134 s->do_cmd = apci3120_ai_cmd;
135 s->cancel = apci3120_cancel;
bb6986f0
HS
136
137 /* Allocate and Initialise AO Subdevice Structures */
138 s = &dev->subdevices[1];
48fdf084 139 if (this_board->i_NbrAoChannel) {
bb6986f0
HS
140 s->type = COMEDI_SUBD_AO;
141 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
48fdf084
HS
142 s->n_chan = this_board->i_NbrAoChannel;
143 s->maxdata = this_board->i_AoMaxdata;
144 s->len_chanlist = this_board->i_NbrAoChannel;
0bb482e2 145 s->range_table = &range_apci3120_ao;
805077b9 146 s->insn_write = apci3120_ao_insn_write;
bb6986f0
HS
147 } else {
148 s->type = COMEDI_SUBD_UNUSED;
149 }
f2c872e1 150
bb6986f0
HS
151 /* Allocate and Initialise DI Subdevice Structures */
152 s = &dev->subdevices[2];
f2c872e1
HS
153 s->type = COMEDI_SUBD_DI;
154 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
155 s->n_chan = this_board->i_NbrDiChannel;
156 s->maxdata = 1;
157 s->len_chanlist = this_board->i_NbrDiChannel;
158 s->range_table = &range_digital;
a7f4b3ca 159 s->insn_bits = apci3120_di_insn_bits;
f2c872e1 160
bb6986f0
HS
161 /* Allocate and Initialise DO Subdevice Structures */
162 s = &dev->subdevices[3];
43deb75d
HS
163 s->type = COMEDI_SUBD_DO;
164 s->subdev_flags =
165 SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
166 s->n_chan = this_board->i_NbrDoChannel;
167 s->maxdata = this_board->i_DoMaxdata;
168 s->len_chanlist = this_board->i_NbrDoChannel;
169 s->range_table = &range_digital;
66511843 170 s->insn_bits = apci3120_do_insn_bits;
bb6986f0
HS
171
172 /* Allocate and Initialise Timer Subdevice Structures */
173 s = &dev->subdevices[4];
53b168b9
HS
174 s->type = COMEDI_SUBD_TIMER;
175 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
176 s->n_chan = 1;
177 s->maxdata = 0;
178 s->len_chanlist = 1;
179 s->range_table = &range_digital;
180
805077b9
FA
181 s->insn_write = apci3120_write_insn_timer;
182 s->insn_read = apci3120_read_insn_timer;
183 s->insn_config = apci3120_config_insn_timer;
bb6986f0 184
805077b9 185 apci3120_reset(dev);
bb6986f0
HS
186 return 0;
187}
188
189static void apci3120_detach(struct comedi_device *dev)
190{
bb6986f0
HS
191 struct addi_private *devpriv = dev->private;
192
aac307f9
HS
193 if (dev->iobase)
194 apci3120_reset(dev);
195 comedi_pci_detach(dev);
bb6986f0 196 if (devpriv) {
fbfd9c8a
IA
197 unsigned int i;
198
199 for (i = 0; i < 2; i++) {
200 if (devpriv->ul_DmaBufferVirtual[i]) {
201 dma_free_coherent(dev->hw_dev,
202 devpriv->ui_DmaBufferSize[i],
203 devpriv->
204 ul_DmaBufferVirtual[i],
205 devpriv->ul_DmaBufferHw[i]);
206 }
bb6986f0
HS
207 }
208 }
bb6986f0
HS
209}
210
20a22b70
HS
211static struct comedi_driver apci3120_driver = {
212 .driver_name = "addi_apci_3120",
213 .module = THIS_MODULE,
891e62c3 214 .auto_attach = apci3120_auto_attach,
bb6986f0 215 .detach = apci3120_detach,
20a22b70
HS
216};
217
a690b7e5 218static int apci3120_pci_probe(struct pci_dev *dev,
b8f4ac23 219 const struct pci_device_id *id)
20a22b70 220{
b8f4ac23 221 return comedi_pci_auto_config(dev, &apci3120_driver, id->driver_data);
20a22b70
HS
222}
223
41e043fc 224static const struct pci_device_id apci3120_pci_table[] = {
aee351b2
IA
225 { PCI_VDEVICE(AMCC, 0x818d), BOARD_APCI3120 },
226 { PCI_VDEVICE(AMCC, 0x828d), BOARD_APCI3001 },
317285d7
HS
227 { 0 }
228};
20a22b70 229MODULE_DEVICE_TABLE(pci, apci3120_pci_table);
317285d7 230
20a22b70
HS
231static struct pci_driver apci3120_pci_driver = {
232 .name = "addi_apci_3120",
233 .id_table = apci3120_pci_table,
234 .probe = apci3120_pci_probe,
9901a4d7 235 .remove = comedi_pci_auto_unconfig,
20a22b70
HS
236};
237module_comedi_pci_driver(apci3120_driver, apci3120_pci_driver);
90f703d3
AT
238
239MODULE_AUTHOR("Comedi http://www.comedi.org");
b5ebcaa8 240MODULE_DESCRIPTION("ADDI-DATA APCI-3120, Analog input board");
90f703d3 241MODULE_LICENSE("GPL");
This page took 0.517103 seconds and 5 git commands to generate.