summaryrefslogtreecommitdiff
path: root/drivers/staging/comedi/drivers/comedi_8254.h
blob: 7faa2185282ef52cf65a054db84627628b40ca07 (plain)
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
// 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>

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 - private data used by this module
 * @iobase:		PIO base address of the registers (in/out)
 * @mmio:		MMIO base address of the registers (read/write)
 * @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 {
	unsigned long iobase;
	void __iomem *mmio;
	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);

struct comedi_8254 *comedi_8254_init(unsigned long iobase,
				     unsigned int osc_base,
				     unsigned int iosize,
				     unsigned int regshift);
struct comedi_8254 *comedi_8254_mm_init(void __iomem *mmio,
					unsigned int osc_base,
					unsigned int iosize,
					unsigned int regshift);

#endif	/* _COMEDI_8254_H */