xref: /linux/drivers/ata/pata_parport/fit3.c (revision 7ca26efb09a1543fddb29308ea3b63b66cb5d3ee)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * (c) 1998  Grant R. Guenther <grant@torque.net>
4  *
5  * fit3.c is a low-level protocol driver for newer models
6  * of the Fidelity International Technology parallel port adapter.
7  * This adapter is used in their TransDisk 3000 portable
8  * hard-drives, as well as CD-ROM, PD-CD and other devices.
9  *
10  * The TD-2000 and certain older devices use a different protocol.
11  * Try the fit2 protocol module with them.
12  *
13  * NB:  The FIT adapters do not appear to support the control
14  * registers.  So, we map ALT_STATUS to STATUS and NO-OP writes
15  * to the device control register - this means that IDE reset
16  * will not work on these devices.
17  */
18 
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/delay.h>
22 #include <linux/kernel.h>
23 #include <linux/types.h>
24 #include <linux/wait.h>
25 #include <asm/io.h>
26 #include "pata_parport.h"
27 
28 #define j44(a, b)	(((a >> 3) & 0x0f) | ((b << 1) & 0xf0))
29 
30 #define w7(byte)	out_p(7, byte)
31 #define r7()		(in_p(7) & 0xff)
32 
33 /*
34  * cont = 0 - access the IDE register file
35  * cont = 1 - access the IDE command set
36  */
37 
38 static void fit3_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
39 {
40 	if (cont == 1)
41 		return;
42 
43 	switch (pi->mode) {
44 	case 0:
45 	case 1:
46 		w2(0xc); w0(regr); w2(0x8); w2(0xc);
47 		w0(val); w2(0xd);
48 		w0(0);   w2(0xc);
49 		break;
50 	case 2:
51 		w2(0xc); w0(regr); w2(0x8); w2(0xc);
52 		w4(val); w4(0);
53 		w2(0xc);
54 		break;
55 	}
56 }
57 
58 static int fit3_read_regr(struct pi_adapter *pi, int cont, int regr)
59 {
60 	int  a, b;
61 
62 	if (cont) {
63 		if (regr != 6)
64 			return 0xff;
65 		regr = 7;
66 	}
67 
68 	switch (pi->mode) {
69 	case 0:
70 		w2(0xc); w0(regr + 0x10); w2(0x8); w2(0xc);
71 		w2(0xd); a = r1();
72 		w2(0xf); b = r1();
73 		w2(0xc);
74 		return j44(a, b);
75 	case 1:
76 		w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc);
77 		w2(0xec); w2(0xee); w2(0xef); a = r0();
78 		w2(0xc);
79 		return a;
80 	case 2:
81 		w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc);
82 		w2(0xec);
83 		a = r4(); b = r4();
84 		w2(0xc);
85 		return a;
86 	}
87 
88 	return -1;
89 }
90 
91 static void fit3_read_block(struct pi_adapter *pi, char *buf, int count)
92 {
93 	int  k, a, b, c, d;
94 
95 	switch (pi->mode) {
96 	case 0:
97 		w2(0xc); w0(0x10); w2(0x8); w2(0xc);
98 		for (k = 0; k < count / 2; k++) {
99 			w2(0xd); a = r1();
100 			w2(0xf); b = r1();
101 			w2(0xc); c = r1();
102 			w2(0xe); d = r1();
103 			buf[2 * k] = j44(a, b);
104 			buf[2 * k + 1] = j44(c, d);
105 		}
106 		w2(0xc);
107 		break;
108 	case 1:
109 		w2(0xc); w0(0x90); w2(0x8); w2(0xc);
110 		w2(0xec); w2(0xee);
111 		for (k = 0; k < count / 2; k++) {
112 			w2(0xef); a = r0();
113 			w2(0xee); b = r0();
114 			buf[2 * k] = a;
115 			buf[2 * k + 1] = b;
116 		}
117 		w2(0xec);
118 		w2(0xc);
119 		break;
120 	case 2:
121 		w2(0xc); w0(0x90); w2(0x8); w2(0xc);
122 		w2(0xec);
123 		for (k = 0; k < count; k++)
124 			buf[k] = r4();
125 		w2(0xc);
126 		break;
127 	}
128 }
129 
130 static void fit3_write_block(struct pi_adapter *pi, char *buf, int count)
131 {
132 	int k;
133 
134 	switch (pi->mode) {
135 	case 0:
136 	case 1:
137 		w2(0xc); w0(0); w2(0x8); w2(0xc);
138 		for (k = 0; k < count / 2; k++) {
139 			w0(buf[2 * k]); w2(0xd);
140 			w0(buf[2 * k + 1]); w2(0xc);
141 		}
142 		break;
143 	case 2:
144 		w2(0xc); w0(0); w2(0x8); w2(0xc);
145 		for (k = 0; k < count; k++)
146 			w4(buf[k]);
147 		w2(0xc);
148 		break;
149 	}
150 }
151 
152 static void fit3_connect(struct pi_adapter *pi)
153 {
154 	pi->saved_r0 = r0();
155 	pi->saved_r2 = r2();
156 	w2(0xc); w0(0); w2(0xa);
157 	if (pi->mode == 2) {
158 		w2(0xc); w0(0x9);
159 		w2(0x8); w2(0xc);
160 	}
161 }
162 
163 static void fit3_disconnect(struct pi_adapter *pi)
164 {
165 	w2(0xc); w0(0xa); w2(0x8); w2(0xc);
166 	w0(pi->saved_r0);
167 	w2(pi->saved_r2);
168 }
169 
170 static void fit3_log_adapter(struct pi_adapter *pi)
171 {
172 	char *mode_string[3] = { "4-bit", "8-bit", "EPP"};
173 
174 	dev_info(&pi->dev,
175 		 "FIT 3000 adapter at 0x%x, mode %d (%s), delay %d\n",
176 		 pi->port, pi->mode, mode_string[pi->mode], pi->delay);
177 }
178 
179 static struct pi_protocol fit3 = {
180 	.owner		= THIS_MODULE,
181 	.name		= "fit3",
182 	.max_mode	= 3,
183 	.epp_first	= 2,
184 	.default_delay	= 1,
185 	.max_units	= 1,
186 	.write_regr	= fit3_write_regr,
187 	.read_regr	= fit3_read_regr,
188 	.write_block	= fit3_write_block,
189 	.read_block	= fit3_read_block,
190 	.connect	= fit3_connect,
191 	.disconnect	= fit3_disconnect,
192 	.log_adapter	= fit3_log_adapter,
193 };
194 
195 MODULE_LICENSE("GPL");
196 MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>");
197 MODULE_DESCRIPTION("Fidelity International Technology parallel port IDE adapter"
198 		   "(newer models) protocol driver");
199 module_pata_parport_driver(fit3);
200