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
|
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* comedi_8254.h
* Generic 8254 timer/counter support
* Copyright (C) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
*
* COMEDI - Linux Control and Measurement Device Interface
* Copyright (C) 2000 David A. Schleef <ds@schleef.org>
*/
#ifndef _COMEDI_8254_H
#define _COMEDI_8254_H
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
struct comedi_device;
struct comedi_insn;
struct comedi_subdevice;
/*
* Common oscillator base values in nanoseconds
*/
#define I8254_OSC_BASE_10MHZ 100
#define I8254_OSC_BASE_5MHZ 200
#define I8254_OSC_BASE_4MHZ 250
#define I8254_OSC_BASE_2MHZ 500
#define I8254_OSC_BASE_1MHZ 1000
#define I8254_OSC_BASE_100KHZ 10000
#define I8254_OSC_BASE_10KHZ 100000
#define I8254_OSC_BASE_1KHZ 1000000
/*
* I/O access size used to read/write registers
*/
#define I8254_IO8 1
#define I8254_IO16 2
#define I8254_IO32 4
/*
* Register map for generic 8254 timer (I8254_IO8 with 0 regshift)
*/
#define I8254_COUNTER0_REG 0x00
#define I8254_COUNTER1_REG 0x01
#define I8254_COUNTER2_REG 0x02
#define I8254_CTRL_REG 0x03
#define I8254_CTRL_SEL_CTR(x) ((x) << 6)
#define I8254_CTRL_READBACK(x) (I8254_CTRL_SEL_CTR(3) | BIT(x))
#define I8254_CTRL_READBACK_COUNT I8254_CTRL_READBACK(4)
#define I8254_CTRL_READBACK_STATUS I8254_CTRL_READBACK(5)
#define I8254_CTRL_READBACK_SEL_CTR(x) (2 << (x))
#define I8254_CTRL_RW(x) (((x) & 0x3) << 4)
#define I8254_CTRL_LATCH I8254_CTRL_RW(0)
#define I8254_CTRL_LSB_ONLY I8254_CTRL_RW(1)
#define I8254_CTRL_MSB_ONLY I8254_CTRL_RW(2)
#define I8254_CTRL_LSB_MSB I8254_CTRL_RW(3)
/* counter maps zero to 0x10000 */
#define I8254_MAX_COUNT 0x10000
struct comedi_8254;
/**
* typedef comedi_8254_iocb_fn - call-back function type for 8254 register access
* @i8254: pointer to struct comedi_8254
* @dir: direction (0 = read, 1 = write)
* @reg: register number
* @val: value to write
*
* Return: Register value when reading, 0 when writing.
*/
typedef unsigned int comedi_8254_iocb_fn(struct comedi_8254 *i8254, int dir,
unsigned int reg, unsigned int val);
/**
* struct comedi_8254 - private data used by this module
* @iocb: I/O call-back function for register access
* @context: context for register access (e.g. a base address)
* @iosize: I/O size used to access the registers (b/w/l)
* @regshift: register gap shift
* @osc_base: cascaded oscillator speed in ns
* @divisor: divisor for single counter
* @divisor1: divisor loaded into first cascaded counter
* @divisor2: divisor loaded into second cascaded counter
* #next_div: next divisor for single counter
* @next_div1: next divisor to use for first cascaded counter
* @next_div2: next divisor to use for second cascaded counter
* @clock_src; current clock source for each counter (driver specific)
* @gate_src; current gate source for each counter (driver specific)
* @busy: flags used to indicate that a counter is "busy"
* @insn_config: driver specific (*insn_config) callback
*/
struct comedi_8254 {
comedi_8254_iocb_fn *iocb;
unsigned long context;
unsigned int iosize;
unsigned int regshift;
unsigned int osc_base;
unsigned int divisor;
unsigned int divisor1;
unsigned int divisor2;
unsigned int next_div;
unsigned int next_div1;
unsigned int next_div2;
unsigned int clock_src[3];
unsigned int gate_src[3];
bool busy[3];
int (*insn_config)(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
};
unsigned int comedi_8254_status(struct comedi_8254 *i8254,
unsigned int counter);
unsigned int comedi_8254_read(struct comedi_8254 *i8254, unsigned int counter);
void comedi_8254_write(struct comedi_8254 *i8254,
unsigned int counter, unsigned int val);
int comedi_8254_set_mode(struct comedi_8254 *i8254,
unsigned int counter, unsigned int mode);
int comedi_8254_load(struct comedi_8254 *i8254,
unsigned int counter, unsigned int val, unsigned int mode);
void comedi_8254_pacer_enable(struct comedi_8254 *i8254,
unsigned int counter1, unsigned int counter2,
bool enable);
void comedi_8254_update_divisors(struct comedi_8254 *i8254);
void comedi_8254_cascade_ns_to_timer(struct comedi_8254 *i8254,
unsigned int *nanosec, unsigned int flags);
void comedi_8254_ns_to_timer(struct comedi_8254 *i8254,
unsigned int *nanosec, unsigned int flags);
void comedi_8254_set_busy(struct comedi_8254 *i8254,
unsigned int counter, bool busy);
void comedi_8254_subdevice_init(struct comedi_subdevice *s,
struct comedi_8254 *i8254);
#ifdef CONFIG_HAS_IOPORT
struct comedi_8254 *comedi_8254_io_alloc(unsigned long iobase,
unsigned int osc_base,
unsigned int iosize,
unsigned int regshift);
#else
static inline struct comedi_8254 *comedi_8254_io_alloc(unsigned long iobase,
unsigned int osc_base,
unsigned int iosize,
unsigned int regshift)
{
return ERR_PTR(-ENXIO);
}
#endif
struct comedi_8254 *comedi_8254_mm_alloc(void __iomem *mmio,
unsigned int osc_base,
unsigned int iosize,
unsigned int regshift);
#endif /* _COMEDI_8254_H */
|