staging: comedi: adl_pci9111: fix incorrect irq passed to request_irq()
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / 8253.h
1 /*
2     comedi/drivers/8253.h
3     Header file for 8253
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23
24 #ifndef _8253_H
25 #define _8253_H
26
27 #include "../comedi.h"
28
29 #define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div
30
31 static inline void i8253_cascade_ns_to_timer_2div_old(int i8253_osc_base,
32                                                       unsigned int *d1,
33                                                       unsigned int *d2,
34                                                       unsigned int *nanosec,
35                                                       int round_mode)
36 {
37         int divider;
38         int div1, div2;
39         int div1_glb, div2_glb, ns_glb;
40         int div1_lub, div2_lub, ns_lub;
41         int ns;
42
43         divider = (*nanosec + i8253_osc_base / 2) / i8253_osc_base;
44
45         /* find 2 integers 1<={x,y}<=65536 such that x*y is
46            close to divider */
47
48         div1_lub = div2_lub = 0;
49         div1_glb = div2_glb = 0;
50
51         ns_glb = 0;
52         ns_lub = 0xffffffff;
53
54         div2 = 0x10000;
55         for (div1 = divider / 65536 + 1; div1 < div2; div1++) {
56                 div2 = divider / div1;
57
58                 ns = i8253_osc_base * div1 * div2;
59                 if (ns <= *nanosec && ns > ns_glb) {
60                         ns_glb = ns;
61                         div1_glb = div1;
62                         div2_glb = div2;
63                 }
64
65                 div2++;
66                 if (div2 <= 65536) {
67                         ns = i8253_osc_base * div1 * div2;
68                         if (ns > *nanosec && ns < ns_lub) {
69                                 ns_lub = ns;
70                                 div1_lub = div1;
71                                 div2_lub = div2;
72                         }
73                 }
74         }
75
76         *nanosec = div1_lub * div2_lub * i8253_osc_base;
77         *d1 = div1_lub & 0xffff;
78         *d2 = div2_lub & 0xffff;
79         return;
80 }
81
82 static inline void i8253_cascade_ns_to_timer_power(int i8253_osc_base,
83                                                    unsigned int *d1,
84                                                    unsigned int *d2,
85                                                    unsigned int *nanosec,
86                                                    int round_mode)
87 {
88         int div1, div2;
89         int base;
90
91         for (div1 = 2; div1 <= (1 << 16); div1 <<= 1) {
92                 base = i8253_osc_base * div1;
93                 round_mode &= TRIG_ROUND_MASK;
94                 switch (round_mode) {
95                 case TRIG_ROUND_NEAREST:
96                 default:
97                         div2 = (*nanosec + base / 2) / base;
98                         break;
99                 case TRIG_ROUND_DOWN:
100                         div2 = (*nanosec) / base;
101                         break;
102                 case TRIG_ROUND_UP:
103                         div2 = (*nanosec + base - 1) / base;
104                         break;
105                 }
106                 if (div2 < 2)
107                         div2 = 2;
108                 if (div2 <= 65536) {
109                         *nanosec = div2 * base;
110                         *d1 = div1 & 0xffff;
111                         *d2 = div2 & 0xffff;
112                         return;
113                 }
114         }
115
116         /* shouldn't get here */
117         div1 = 0x10000;
118         div2 = 0x10000;
119         *nanosec = div1 * div2 * i8253_osc_base;
120         *d1 = div1 & 0xffff;
121         *d2 = div2 & 0xffff;
122 }
123
124 static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base,
125                                                   unsigned int *d1,
126                                                   unsigned int *d2,
127                                                   unsigned int *nanosec,
128                                                   int round_mode)
129 {
130         unsigned int divider;
131         unsigned int div1, div2;
132         unsigned int div1_glb, div2_glb, ns_glb;
133         unsigned int div1_lub, div2_lub, ns_lub;
134         unsigned int ns;
135         unsigned int start;
136         unsigned int ns_low, ns_high;
137         static const unsigned int max_count = 0x10000;
138         /* exit early if everything is already correct (this can save time
139          * since this function may be called repeatedly during command tests
140          * and execution) */
141         div1 = *d1 ? *d1 : max_count;
142         div2 = *d2 ? *d2 : max_count;
143         divider = div1 * div2;
144         if (div1 * div2 * i8253_osc_base == *nanosec &&
145             div1 > 1 && div1 <= max_count && div2 > 1 && div2 <= max_count &&
146             /* check for overflow */
147             divider > div1 && divider > div2 &&
148             divider * i8253_osc_base > divider &&
149             divider * i8253_osc_base > i8253_osc_base) {
150                 return;
151         }
152
153         divider = *nanosec / i8253_osc_base;
154
155         div1_lub = div2_lub = 0;
156         div1_glb = div2_glb = 0;
157
158         ns_glb = 0;
159         ns_lub = 0xffffffff;
160
161         div2 = max_count;
162         start = divider / div2;
163         if (start < 2)
164                 start = 2;
165         for (div1 = start; div1 <= divider / div1 + 1 && div1 <= max_count;
166              div1++) {
167                 for (div2 = divider / div1;
168                      div1 * div2 <= divider + div1 + 1 && div2 <= max_count;
169                      div2++) {
170                         ns = i8253_osc_base * div1 * div2;
171                         if (ns <= *nanosec && ns > ns_glb) {
172                                 ns_glb = ns;
173                                 div1_glb = div1;
174                                 div2_glb = div2;
175                         }
176                         if (ns >= *nanosec && ns < ns_lub) {
177                                 ns_lub = ns;
178                                 div1_lub = div1;
179                                 div2_lub = div2;
180                         }
181                 }
182         }
183
184         round_mode &= TRIG_ROUND_MASK;
185         switch (round_mode) {
186         case TRIG_ROUND_NEAREST:
187         default:
188                 ns_high = div1_lub * div2_lub * i8253_osc_base;
189                 ns_low = div1_glb * div2_glb * i8253_osc_base;
190                 if (ns_high - *nanosec < *nanosec - ns_low) {
191                         div1 = div1_lub;
192                         div2 = div2_lub;
193                 } else {
194                         div1 = div1_glb;
195                         div2 = div2_glb;
196                 }
197                 break;
198         case TRIG_ROUND_UP:
199                 div1 = div1_lub;
200                 div2 = div2_lub;
201                 break;
202         case TRIG_ROUND_DOWN:
203                 div1 = div1_glb;
204                 div2 = div2_glb;
205                 break;
206         }
207
208         *nanosec = div1 * div2 * i8253_osc_base;
209         /*  masking is done since counter maps zero to 0x10000 */
210         *d1 = div1 & 0xffff;
211         *d2 = div2 & 0xffff;
212         return;
213 }
214
215 #ifndef CMDTEST
216 /* i8254_load programs 8254 counter chip.  It should also work for the 8253.
217  * base_address is the lowest io address
218  * for the chip (the address of counter 0).
219  * counter_number is the counter you want to load (0,1 or 2)
220  * count is the number to load into the counter.
221  *
222  * You probably want to use mode 2.
223  *
224  * Use i8254_mm_load() if you board uses memory-mapped io, it is
225  * the same as i8254_load() except it uses writeb() instead of outb().
226  *
227  * Neither i8254_load() or i8254_read() do their loading/reading
228  * atomically.  The 16 bit read/writes are performed with two successive
229  * 8 bit read/writes.  So if two parts of your driver do a load/read on
230  * the same counter, it may be necessary to protect these functions
231  * with a spinlock.
232  *
233  * FMH
234  */
235
236 #define i8254_control_reg       3
237
238 static inline int i8254_load(unsigned long base_address, unsigned int regshift,
239                              unsigned int counter_number, unsigned int count,
240                              unsigned int mode)
241 {
242         unsigned int byte;
243
244         if (counter_number > 2)
245                 return -1;
246         if (count > 0xffff)
247                 return -1;
248         if (mode > 5)
249                 return -1;
250         if ((mode == 2 || mode == 3) && count == 1)
251                 return -1;
252
253         byte = counter_number << 6;
254         byte |= 0x30;           /*  load low then high byte */
255         byte |= (mode << 1);    /*  set counter mode */
256         outb(byte, base_address + (i8254_control_reg << regshift));
257         byte = count & 0xff;    /*  lsb of counter value */
258         outb(byte, base_address + (counter_number << regshift));
259         byte = (count >> 8) & 0xff;     /*  msb of counter value */
260         outb(byte, base_address + (counter_number << regshift));
261
262         return 0;
263 }
264
265 static inline int i8254_mm_load(void __iomem *base_address,
266                                 unsigned int regshift,
267                                 unsigned int counter_number,
268                                 unsigned int count,
269                                 unsigned int mode)
270 {
271         unsigned int byte;
272
273         if (counter_number > 2)
274                 return -1;
275         if (count > 0xffff)
276                 return -1;
277         if (mode > 5)
278                 return -1;
279         if ((mode == 2 || mode == 3) && count == 1)
280                 return -1;
281
282         byte = counter_number << 6;
283         byte |= 0x30;           /*  load low then high byte */
284         byte |= (mode << 1);    /*  set counter mode */
285         writeb(byte, base_address + (i8254_control_reg << regshift));
286         byte = count & 0xff;    /*  lsb of counter value */
287         writeb(byte, base_address + (counter_number << regshift));
288         byte = (count >> 8) & 0xff;     /*  msb of counter value */
289         writeb(byte, base_address + (counter_number << regshift));
290
291         return 0;
292 }
293
294 /* Returns 16 bit counter value, should work for 8253 also.*/
295 static inline int i8254_read(unsigned long base_address, unsigned int regshift,
296                              unsigned int counter_number)
297 {
298         unsigned int byte;
299         int ret;
300
301         if (counter_number > 2)
302                 return -1;
303
304         /*  latch counter */
305         byte = counter_number << 6;
306         outb(byte, base_address + (i8254_control_reg << regshift));
307
308         /*  read lsb */
309         ret = inb(base_address + (counter_number << regshift));
310         /*  read msb */
311         ret += inb(base_address + (counter_number << regshift)) << 8;
312
313         return ret;
314 }
315
316 static inline int i8254_mm_read(void __iomem *base_address,
317                                 unsigned int regshift,
318                                 unsigned int counter_number)
319 {
320         unsigned int byte;
321         int ret;
322
323         if (counter_number > 2)
324                 return -1;
325
326         /*  latch counter */
327         byte = counter_number << 6;
328         writeb(byte, base_address + (i8254_control_reg << regshift));
329
330         /*  read lsb */
331         ret = readb(base_address + (counter_number << regshift));
332         /*  read msb */
333         ret += readb(base_address + (counter_number << regshift)) << 8;
334
335         return ret;
336 }
337
338 /* Loads 16 bit initial counter value, should work for 8253 also. */
339 static inline void i8254_write(unsigned long base_address,
340                                unsigned int regshift,
341                                unsigned int counter_number, unsigned int count)
342 {
343         unsigned int byte;
344
345         if (counter_number > 2)
346                 return;
347
348         byte = count & 0xff;    /*  lsb of counter value */
349         outb(byte, base_address + (counter_number << regshift));
350         byte = (count >> 8) & 0xff;     /*  msb of counter value */
351         outb(byte, base_address + (counter_number << regshift));
352 }
353
354 static inline void i8254_mm_write(void __iomem *base_address,
355                                   unsigned int regshift,
356                                   unsigned int counter_number,
357                                   unsigned int count)
358 {
359         unsigned int byte;
360
361         if (counter_number > 2)
362                 return;
363
364         byte = count & 0xff;    /*  lsb of counter value */
365         writeb(byte, base_address + (counter_number << regshift));
366         byte = (count >> 8) & 0xff;     /*  msb of counter value */
367         writeb(byte, base_address + (counter_number << regshift));
368 }
369
370 /* Set counter mode, should work for 8253 also.
371  * Note: the 'mode' value is different to that for i8254_load() and comes
372  * from the INSN_CONFIG_8254_SET_MODE command:
373  *   I8254_MODE0, I8254_MODE1, ..., I8254_MODE5
374  * OR'ed with:
375  *   I8254_BCD, I8254_BINARY
376  */
377 static inline int i8254_set_mode(unsigned long base_address,
378                                  unsigned int regshift,
379                                  unsigned int counter_number, unsigned int mode)
380 {
381         unsigned int byte;
382
383         if (counter_number > 2)
384                 return -1;
385         if (mode > (I8254_MODE5 | I8254_BINARY))
386                 return -1;
387
388         byte = counter_number << 6;
389         byte |= 0x30;           /*  load low then high byte */
390         byte |= mode;           /*  set counter mode and BCD|binary */
391         outb(byte, base_address + (i8254_control_reg << regshift));
392
393         return 0;
394 }
395
396 static inline int i8254_mm_set_mode(void __iomem *base_address,
397                                     unsigned int regshift,
398                                     unsigned int counter_number,
399                                     unsigned int mode)
400 {
401         unsigned int byte;
402
403         if (counter_number > 2)
404                 return -1;
405         if (mode > (I8254_MODE5 | I8254_BINARY))
406                 return -1;
407
408         byte = counter_number << 6;
409         byte |= 0x30;           /*  load low then high byte */
410         byte |= mode;           /*  set counter mode and BCD|binary */
411         writeb(byte, base_address + (i8254_control_reg << regshift));
412
413         return 0;
414 }
415
416 static inline int i8254_status(unsigned long base_address,
417                                unsigned int regshift,
418                                unsigned int counter_number)
419 {
420         outb(0xE0 | (2 << counter_number),
421              base_address + (i8254_control_reg << regshift));
422         return inb(base_address + (counter_number << regshift));
423 }
424
425 static inline int i8254_mm_status(void __iomem *base_address,
426                                   unsigned int regshift,
427                                   unsigned int counter_number)
428 {
429         writeb(0xE0 | (2 << counter_number),
430                base_address + (i8254_control_reg << regshift));
431         return readb(base_address + (counter_number << regshift));
432 }
433
434 #endif
435
436 #endif