aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
blob: 98de96953a292f14bd573ec0e5020b510c8a6de5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* Digital Input IRQ Function Selection */
#define APCI1564_DI_INT_OR				(0 << 1)
#define APCI1564_DI_INT_AND				(1 << 1)

/* Digital Input Interrupt Enable Disable. */
#define APCI1564_DI_INT_ENABLE				0x4
#define APCI1564_DI_INT_DISABLE				0xfffffffb

/* Digital Output Interrupt Enable Disable. */
#define APCI1564_DO_VCC_INT_ENABLE			0x1
#define APCI1564_DO_VCC_INT_DISABLE			0xfffffffe
#define APCI1564_DO_CC_INT_ENABLE			0x2
#define APCI1564_DO_CC_INT_DISABLE			0xfffffffd

/* TIMER COUNTER WATCHDOG DEFINES */
#define ADDIDATA_TIMER					0
#define ADDIDATA_COUNTER				1
#define ADDIDATA_WATCHDOG				2
#define APCI1564_COUNTER1				0
#define APCI1564_COUNTER2				1
#define APCI1564_COUNTER3				2
#define APCI1564_COUNTER4				3

/*
 * devpriv->amcc_iobase Register Map
 */
#define APCI1564_DI_REG					0x04
#define APCI1564_DI_INT_MODE1_REG			0x08
#define APCI1564_DI_INT_MODE2_REG			0x0c
#define APCI1564_DI_INT_STATUS_REG			0x10
#define APCI1564_DI_IRQ_REG				0x14
#define APCI1564_DO_REG					0x18
#define APCI1564_DO_INT_CTRL_REG			0x1c
#define APCI1564_DO_INT_STATUS_REG			0x20
#define APCI1564_DO_IRQ_REG				0x24
#define APCI1564_WDOG_REG				0x28
#define APCI1564_WDOG_RELOAD_REG			0x2c
#define APCI1564_WDOG_TIMEBASE_REG			0x30
#define APCI1564_WDOG_CTRL_REG				0x34
#define APCI1564_WDOG_STATUS_REG			0x38
#define APCI1564_WDOG_IRQ_REG				0x3c
#define APCI1564_WDOG_WARN_TIMEVAL_REG			0x40
#define APCI1564_WDOG_WARN_TIMEBASE_REG			0x44
#define APCI1564_TIMER_REG				0x48
#define APCI1564_TIMER_RELOAD_REG			0x4c
#define APCI1564_TIMER_TIMEBASE_REG			0x50
#define APCI1564_TIMER_CTRL_REG				0x54
#define APCI1564_TIMER_STATUS_REG			0x58
#define APCI1564_TIMER_IRQ_REG				0x5c
#define APCI1564_TIMER_WARN_TIMEVAL_REG			0x60
#define APCI1564_TIMER_WARN_TIMEBASE_REG		0x64

/*
 * dev->iobase Register Map
 */
#define APCI1564_COUNTER_REG(x)				(0x00 + ((x) * 0x20))
#define APCI1564_COUNTER_RELOAD_REG(x)			(0x04 + ((x) * 0x20))
#define APCI1564_COUNTER_TIMEBASE_REG(x)		(0x08 + ((x) * 0x20))
#define APCI1564_COUNTER_CTRL_REG(x)			(0x0c + ((x) * 0x20))
#define APCI1564_COUNTER_STATUS_REG(x)			(0x10 + ((x) * 0x20))
#define APCI1564_COUNTER_IRQ_REG(x)			(0x14 + ((x) * 0x20))
#define APCI1564_COUNTER_WARN_TIMEVAL_REG(x)		(0x18 + ((x) * 0x20))
#define APCI1564_COUNTER_WARN_TIMEBASE_REG(x)		(0x1c + ((x) * 0x20))

/*
 * Configures The Timer or Counter
 *
 * data[0] Configure as: 0 = Timer, 1 = Counter
 * data[1] 1 = Enable Interrupt, 0 = Disable Interrupt
 * data[2] Time Unit
 * data[3] Reload Value
 * data[4] Timer Mode
 * data[5] Timer Counter Watchdog Number
 * data[6] Counter Direction
 */
static int apci1564_timer_config(struct comedi_device *dev,
				 struct comedi_subdevice *s,
				 struct comedi_insn *insn,
				 unsigned int *data)
{
	struct apci1564_private *devpriv = dev->private;
	unsigned int ul_Command1 = 0;

	devpriv->tsk_current = current;
	if (data[0] == ADDIDATA_TIMER) {
		/* First Stop The Timer */
		ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
		ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
		/* Stop The Timer */
		outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);

		devpriv->timer_select_mode = ADDIDATA_TIMER;
		if (data[1] == 1) {
			/* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */
			outl(0x02, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
			outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG);
			outl(0x0, devpriv->amcc_iobase + APCI1564_DO_IRQ_REG);
			outl(0x0, devpriv->amcc_iobase + APCI1564_WDOG_IRQ_REG);
			outl(0x0, dev->iobase +
			    APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER1));
			outl(0x0, dev->iobase +
			    APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER2));
			outl(0x0, dev->iobase +
			    APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER3));
			outl(0x0, dev->iobase +
			    APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER4));
		} else {
			/* disable Timer interrupt */
			outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
		}

		/*  Loading Timebase */
		outl(data[2], devpriv->amcc_iobase + APCI1564_TIMER_TIMEBASE_REG);

		/* Loading the Reload value */
		outl(data[3], devpriv->amcc_iobase + APCI1564_TIMER_RELOAD_REG);

		ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
		ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL;
		/* mode 2 */
		outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
	} else if (data[0] == ADDIDATA_COUNTER) {
		devpriv->timer_select_mode = ADDIDATA_COUNTER;
		devpriv->mode_select_register = data[5];

		/* First Stop The Counter */
		ul_Command1 = inl(dev->iobase +
				 APCI1564_COUNTER_CTRL_REG(data[5] - 1));
		ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
		/* Stop The Timer */
		outl(ul_Command1, dev->iobase +
					APCI1564_COUNTER_CTRL_REG(data[5] - 1));

		/* Set the reload value */
		outl(data[3], dev->iobase +
					APCI1564_COUNTER_RELOAD_REG(data[5] - 1));

		/* Set the mode :             */
		/* - Disable the hardware     */
		/* - Disable the counter mode */
		/* - Disable the warning      */
		/* - Disable the reset        */
		/* - Disable the timer mode   */
		/* - Enable the counter mode  */

		ul_Command1 =
			(ul_Command1 & 0xFFFC19E2UL) | 0x80000UL |
			(unsigned int) ((unsigned int) data[4] << 16UL);
		outl(ul_Command1, dev->iobase +
					APCI1564_COUNTER_CTRL_REG(data[5] - 1));

		/*  Enable or Disable Interrupt */
		ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1);
		outl(ul_Command1, dev->iobase +
					APCI1564_COUNTER_CTRL_REG(data[5] - 1));

		/* Set the Up/Down selection */
		ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18);
		outl(ul_Command1, dev->iobase +
					APCI1564_COUNTER_CTRL_REG(data[5] - 1));
	} else {
		dev_err(dev->class_dev, "Invalid subdevice.\n");
	}
	return insn->n;
}

/*
 * Start / Stop The Selected Timer or Counter
 *
 * data[0] Configure as: 0 = Timer, 1 = Counter
 * data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter)
 */
static int apci1564_timer_write(struct comedi_device *dev,
				struct comedi_subdevice *s,
				struct comedi_insn *insn,
				unsigned int *data)
{
	struct apci1564_private *devpriv = dev->private;
	unsigned int ul_Command1 = 0;

	if (devpriv->timer_select_mode == ADDIDATA_TIMER) {
		if (data[1] == 1) {
			ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;

			/* Enable the Timer */
			outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
		} else if (data[1] == 0) {
			/* Stop The Timer */

			ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
			ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
			outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
		}
	} else if (devpriv->timer_select_mode == ADDIDATA_COUNTER) {
		ul_Command1 =
			inl(dev->iobase +
			   APCI1564_COUNTER_CTRL_REG(devpriv->mode_select_register - 1));
		if (data[1] == 1) {
			/* Start the Counter subdevice */
			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
		} else if (data[1] == 0) {
			/*  Stops the Counter subdevice */
			ul_Command1 = 0;

		} else if (data[1] == 2) {
			/*  Clears the Counter subdevice */
			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400;
		}
		outl(ul_Command1, dev->iobase +
		     APCI1564_COUNTER_CTRL_REG(devpriv->mode_select_register - 1));
	} else {
		dev_err(dev->class_dev, "Invalid subdevice.\n");
	}
	return insn->n;
}

/*
 * Read The Selected Timer or Counter
 */
static int apci1564_timer_read(struct comedi_device *dev,
			       struct comedi_subdevice *s,
			       struct comedi_insn *insn,
			       unsigned int *data)
{
	struct apci1564_private *devpriv = dev->private;
	unsigned int ul_Command1 = 0;

	if (devpriv->timer_select_mode == ADDIDATA_TIMER) {
		/*  Stores the status of the Timer */
		data[0] = inl(devpriv->amcc_iobase + APCI1564_TIMER_STATUS_REG) & 0x1;

		/*  Stores the Actual value of the Timer */
		data[1] = inl(devpriv->amcc_iobase + APCI1564_TIMER_REG);
	} else if (devpriv->timer_select_mode == ADDIDATA_COUNTER) {
		/*  Read the Counter Actual Value. */
		data[0] =
			inl(dev->iobase +
			    APCI1564_COUNTER_REG(devpriv->mode_select_register - 1));
		ul_Command1 =
			inl(dev->iobase +
			    APCI1564_COUNTER_STATUS_REG(devpriv->mode_select_register - 1));

		/* Get the software trigger status */
		data[1] = (unsigned char) ((ul_Command1 >> 1) & 1);

		/* Get the hardware trigger status */
		data[2] = (unsigned char) ((ul_Command1 >> 2) & 1);

		/* Get the software clear status */
		data[3] = (unsigned char) ((ul_Command1 >> 3) & 1);

		/* Get the overflow status */
		data[4] = (unsigned char) ((ul_Command1 >> 0) & 1);
	} else {
		dev_err(dev->class_dev, "Invalid subdevice.\n");
	}
	return insn->n;
}