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
/* SPDX-License-Identifier: GPL-2.0 */

/***************************************************************************
 *   Author: Frank Mori Hess <fmh6jj@gmail.com>
 *   copyright: (C) 2006, 2010, 2015 Fluke Corporation
 ***************************************************************************/

#include <linux/compiler.h>
#include <linux/dmaengine.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include "nec7210.h"

struct fluke_priv {
	struct nec7210_priv nec7210_priv;
	struct resource *gpib_iomem_res;
	struct resource *write_transfer_counter_res;
	struct resource *dma_port_res;
	int irq;
	struct dma_chan *dma_channel;
	u8 *dma_buffer;
	int dma_buffer_size;
	void __iomem *write_transfer_counter;
};

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

enum cb7210_page_in {
	ISR0_IMR0_PAGE = 1,
	BUS_STATUS_PAGE = 1,
	STATE1_PAGE = 1
};

/* IMR0 -- Interrupt Mode Register 0 */
enum imr0_bits {
	FLUKE_IFCIE_BIT = 0x8,	/* interface clear interrupt */
};

/* ISR0 -- Interrupt Status Register 0 */
enum isr0_bits {
	FLUKE_IFCI_BIT = 0x8,	/* interface clear interrupt */
};

enum state1_bits {
	SOURCE_HANDSHAKE_SIDS_BITS = 0x0, /* source idle state */
	SOURCE_HANDSHAKE_SGNS_BITS = 0x1, /* source generate state */
	SOURCE_HANDSHAKE_SDYS_BITS = 0x2, /* source delay state */
	SOURCE_HANDSHAKE_STRS_BITS = 0x5, /* source transfer state */
	SOURCE_HANDSHAKE_MASK = 0x7
};

// we customized the cb7210 vhdl to give the "data in" status
// on the unused bit 7 of the address0 register.
enum cb7210_address0 {
	DATA_IN_STATUS = 0x80
};

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

// don't use without locking nec_priv->register_page_lock
static inline uint8_t fluke_read_byte_nolock(struct nec7210_priv *nec_priv,
					     int register_num)
{
	u8 retval;

	retval = readl(nec_priv->mmiobase + register_num * nec_priv->offset);
	return retval;
}

// don't use without locking nec_priv->register_page_lock
static inline void fluke_write_byte_nolock(struct nec7210_priv *nec_priv, uint8_t data,
					   int register_num)
{
	writel(data, nec_priv->mmiobase + register_num * nec_priv->offset);
}

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

	spin_lock_irqsave(&nec_priv->register_page_lock, flags);
	fluke_write_byte_nolock(nec_priv, cb7210_page_in_bits(page), AUXMR);
	udelay(1);
	/* chip auto clears the page after a read */
	retval = fluke_read_byte_nolock(nec_priv, register_num);
	spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
	return retval;
}

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

	spin_lock_irqsave(&nec_priv->register_page_lock, flags);
	fluke_write_byte_nolock(nec_priv, cb7210_page_in_bits(page), AUXMR);
	udelay(1);
	fluke_write_byte_nolock(nec_priv, data, register_num);
	spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
}

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,
};

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_NBAF = 0xe,	// new byte available false (also clears seoi)
	AUX_LO_SPEED = 0x40,
	AUX_HI_SPEED = 0x41,
};

enum {
	fluke_reg_offset = 4,
	fluke_num_regs = 8,
	write_transfer_counter_mask = 0x7ff,
};
掌心的温暖 是你紧握著的光芒 透过了指缝 一星半点投奔向远方