summaryrefslogtreecommitdiff
path: root/drivers/staging/gpib/cb7210/cb7210.h
blob: 2108fe7a8ce5dd63ca38bac718f2a3fea2205138 (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
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
/* SPDX-License-Identifier: GPL-2.0 */

/***************************************************************************
 *    copyright            : (C) 2002 by Frank Mori Hess
 ***************************************************************************/

#include "nec7210.h"
#include "gpibP.h"
#include "amccs5933.h"

#include <linux/delay.h>
#include <linux/interrupt.h>

enum {
	PCI_DEVICE_ID_CBOARDS_PCI_GPIB = 0x6,
	PCI_DEVICE_ID_CBOARDS_CPCI_GPIB = 0xe,
};

enum pci_chip {
	PCI_CHIP_NONE = 0,
	PCI_CHIP_AMCC_S5933,
	PCI_CHIP_QUANCOM
};

// struct which defines private_data for cb7210 boards
struct cb7210_priv {
	struct nec7210_priv nec7210_priv;
	struct pci_dev *pci_device;
	// base address of amccs5933 pci chip
	unsigned long amcc_iobase;
	unsigned long fifo_iobase;
	unsigned int irq;
	enum pci_chip pci_chip;
	u8 hs_mode_bits;
	unsigned out_fifo_half_empty : 1;
	unsigned in_fifo_half_full : 1;
};

// pci-gpib register offset
static const int cb7210_reg_offset = 1;

// uses 10 ioports
static const int cb7210_iosize = 10;

// fifo size in bytes
static const int cb7210_fifo_size = 2048;
static const int cb7210_fifo_width = 2;

// cb7210 specific registers and bits
enum cb7210_regs {
	BUS_STATUS = 0x7,
};

enum cb7210_page_in {
	BUS_STATUS_PAGE = 1,
};

enum hs_regs {
	//write registers
	HS_MODE = 0x8,	/* HS_MODE register */
	HS_INT_LEVEL = 0x9,	/* HS_INT_LEVEL register */
	//read registers
	HS_STATUS = 0x8,	/* HS_STATUS register */
};

static inline u32 nec7210_iobase(const struct cb7210_priv *cb_priv)
{
	return cb_priv->nec7210_priv.iobase;
}

static inline int cb7210_page_in_bits(unsigned int page)
{
	return 0x50 | (page & 0xf);
}

static inline uint8_t cb7210_paged_read_byte(struct cb7210_priv *cb_priv,
					     unsigned int register_num, unsigned int page)
{
	struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
	u8 retval;
	unsigned long flags;

	spin_lock_irqsave(&nec_priv->register_page_lock, flags);
	outb(cb7210_page_in_bits(page), nec7210_iobase(cb_priv) + AUXMR * nec_priv->offset);
	udelay(1);
	retval = inb(nec7210_iobase(cb_priv) + register_num * nec_priv->offset);
	spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
	return retval;
}

// don't use for register_num < 8, since it doesn't lock
static inline uint8_t cb7210_read_byte(const struct cb7210_priv *cb_priv,
				       enum hs_regs register_num)
{
	const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
	u8 retval;

	retval = inb(nec7210_iobase(cb_priv) + register_num * nec_priv->offset);
	return retval;
}

static inline void cb7210_paged_write_byte(struct cb7210_priv *cb_priv, uint8_t data,
					   unsigned int register_num, unsigned int page)
{
	struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
	unsigned long flags;

	spin_lock_irqsave(&nec_priv->register_page_lock, flags);
	outb(cb7210_page_in_bits(page), nec7210_iobase(cb_priv) + AUXMR * nec_priv->offset);
	udelay(1);
	outb(data, nec7210_iobase(cb_priv) + register_num * nec_priv->offset);
	spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
}

// don't use for register_num < 8, since it doesn't lock
static inline void cb7210_write_byte(const struct cb7210_priv *cb_priv, uint8_t data,
				     enum hs_regs register_num)
{
	const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;

	outb(data, nec7210_iobase(cb_priv) + register_num * nec_priv->offset);
}

enum bus_status_bits {
	BSR_ATN_BIT = 0x1,
	BSR_EOI_BIT = 0x2,
	BSR_SRQ_BIT = 0x4,
	BSR_IFC_BIT = 0x8,
	BSR_REN_BIT = 0x10,
	BSR_DAV_BIT = 0x20,
	BSR_NRFD_BIT = 0x40,
	BSR_NDAC_BIT = 0x80,
};

/* CBI 488.2 HS control */

/* when both bit 0 and 1 are set, it
 *   1 clears the transmit state machine to an initial condition
 *   2 clears any residual interrupts left latched on cbi488.2
 *   3 resets all control bits in HS_MODE to zero
 *   4 enables TX empty interrupts
 * when both bit 0 and 1 are zero, then the high speed mode is disabled
 */
enum hs_mode_bits {
	HS_ENABLE_MASK = 0x3,
	HS_TX_ENABLE = (1 << 0),
	HS_RX_ENABLE = (1 << 1),
	HS_HF_INT_EN = (1 << 3),
	HS_CLR_SRQ_INT = (1 << 4),
	HS_CLR_EOI_EMPTY_INT = (1 << 5),
	HS_CLR_HF_INT = (1 << 6),
	HS_SYS_CONTROL = (1 << 7),
};

/* CBI 488.2 status */
enum hs_status_bits {
	HS_FIFO_FULL = (1 << 0),
	HS_HALF_FULL = (1 << 1),
	HS_SRQ_INT = (1 << 2),
	HS_EOI_INT = (1 << 3),
	HS_TX_MSB_NOT_EMPTY = (1 << 4),
	HS_RX_MSB_NOT_EMPTY = (1 << 5),
	HS_TX_LSB_NOT_EMPTY = (1 << 6),
	HS_RX_LSB_NOT_EMPTY = (1 << 7),
};

/* CBI488.2 hs_int_level register */
enum hs_int_level_bits {
	HS_RESET7210 = (1 << 7),
};

static inline unsigned int irq_bits(unsigned int irq)
{
	switch (irq) {
	case 2:
	case 3:
	case 4:
	case 5:
		return irq - 1;
	case 7:
		return 0x5;
	case 10:
		return 0x6;
	case 11:
		return 0x7;
	default:
		return 0;
	}
}

enum cb7210_aux_cmds {
/* AUX_RTL2 is an undocumented aux command which causes cb7210 to assert
 *	(and keep asserted) local rtl message.  This is used in conjunction
 *	with the (stupid) cb7210 implementation
 *	of the normal nec7210 AUX_RTL aux command, which
 *	causes the rtl message to toggle between on and off.
 */
	AUX_RTL2 = 0xd,
	AUX_LO_SPEED = 0x40,
	AUX_HI_SPEED = 0x41,
};