1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * (c) 1997-1998 Grant R. Guenther <grant@torque.net>
4 *
5 * on26.c is a low-level protocol driver for the
6 * OnSpec 90c26 parallel to IDE adapter chip.
7 */
8
9#include <linux/module.h>
10#include <linux/init.h>
11#include <linux/delay.h>
12#include <linux/kernel.h>
13#include <linux/types.h>
14#include <linux/wait.h>
15#include <asm/io.h>
16#include "pata_parport.h"
17
18/*
19 * mode codes: 0 nybble reads, 8-bit writes
20 * 1 8-bit reads and writes
21 * 2 8-bit EPP mode
22 * 3 EPP-16
23 * 4 EPP-32
24 */
25
26#define j44(a, b) (((a >> 4) & 0x0f) | (b & 0xf0))
27
28#define P1 \
29 do { \
30 w2(5); w2(0xd); w2(5); w2(0xd); w2(5); w2(4); \
31 } while (0)
32
33#define P2 \
34 do { \
35 w2(5); w2(7); w2(5); w2(4); \
36 } while (0)
37
38/*
39 * cont = 0 - access the IDE register file
40 * cont = 1 - access the IDE command set
41 */
42
43static int on26_read_regr(struct pi_adapter *pi, int cont, int regr)
44{
45 int a, b, r;
46
47 r = (regr << 2) + 1 + cont;
48
49 switch (pi->mode) {
50 case 0:
51 w0(1); P1; w0(r); P2; w0(0); P1;
52 w2(6); a = r1(); w2(4);
53 w2(6); b = r1(); w2(4);
54 w2(6); w2(4); w2(6); w2(4);
55 return j44(a, b);
56 case 1:
57 w0(1); P1; w0(r); P2; w0(0); P1;
58 w2(0x26); a = r0(); w2(4); w2(0x26); w2(4);
59 return a;
60 case 2:
61 case 3:
62 case 4:
63 w3(1); w3(1); w2(5); w4(r); w2(4);
64 w3(0); w3(0); w2(0x24); a = r4(); w2(4);
65 w2(0x24); (void)r4(); w2(4);
66 return a;
67 }
68
69 return -1;
70}
71
72static void on26_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
73{
74 int r = (regr << 2) + 1 + cont;
75
76 switch (pi->mode) {
77 case 0:
78 case 1:
79 w0(1); P1; w0(r); P2; w0(0); P1;
80 w0(val); P2; w0(val); P2;
81 break;
82 case 2:
83 case 3:
84 case 4:
85 w3(1); w3(1); w2(5); w4(r); w2(4);
86 w3(0); w3(0);
87 w2(5); w4(val); w2(4);
88 w2(5); w4(val); w2(4);
89 break;
90 }
91}
92
93#define CCP(x) \
94 do { \
95 w0(0xfe); w0(0xaa); w0(0x55); w0(0); \
96 w0(0xff); w0(0x87); w0(0x78); w0(x); \
97 w2(4); w2(5); w2(4); w0(0xff); \
98 } while (0)
99
100static void on26_connect(struct pi_adapter *pi)
101{
102 int x;
103
104 pi->saved_r0 = r0();
105 pi->saved_r2 = r2();
106
107 CCP(0x20);
108 if (pi->mode)
109 x = 9;
110 else
111 x = 8;
112
113 w0(2); P1; w0(8); P2;
114 w0(2); P1; w0(x); P2;
115}
116
117static void on26_disconnect(struct pi_adapter *pi)
118{
119 if (pi->mode >= 2) {
120 w3(4); w3(4); w3(4); w3(4);
121 } else {
122 w0(4); P1; w0(4); P1;
123 }
124 CCP(0x30);
125 w0(pi->saved_r0);
126 w2(pi->saved_r2);
127}
128
129#define RESET_WAIT 200
130
131/* hard reset */
132static int on26_test_port(struct pi_adapter *pi)
133{
134 int i, m, d, x = 0, y = 0;
135
136 pi->saved_r0 = r0();
137 pi->saved_r2 = r2();
138
139 d = pi->delay;
140 m = pi->mode;
141 pi->delay = 5;
142 pi->mode = 0;
143
144 w2(0xc);
145
146 CCP(0x30); CCP(0);
147
148 w0(0xfe); w0(0xaa); w0(0x55); w0(0); w0(0xff);
149 i = ((r1() & 0xf0) << 4); w0(0x87);
150 i |= (r1() & 0xf0); w0(0x78);
151 w0(0x20); w2(4); w2(5);
152 i |= ((r1() & 0xf0) >> 4);
153 w2(4); w0(0xff);
154
155 if (i == 0xb5f) {
156 w0(2); P1; w0(0); P2;
157 w0(3); P1; w0(0); P2;
158 w0(2); P1; w0(8); P2; udelay(100);
159 w0(2); P1; w0(0xa); P2; udelay(100);
160 w0(2); P1; w0(8); P2; udelay(1000);
161
162 on26_write_regr(pi, cont: 0, regr: 6, val: 0xa0);
163
164 for (i = 0; i < RESET_WAIT; i++) {
165 on26_write_regr(pi, cont: 0, regr: 6, val: 0xa0);
166 x = on26_read_regr(pi, cont: 0, regr: 7);
167 on26_write_regr(pi, cont: 0, regr: 6, val: 0xb0);
168 y = on26_read_regr(pi, cont: 0, regr: 7);
169 if (!((x & 0x80) || (y & 0x80)))
170 break;
171 mdelay(100);
172 }
173
174 if (i == RESET_WAIT)
175 dev_err(&pi->dev,
176 "on26: Device reset failed (%x,%x)\n", x, y);
177
178 w0(4); P1; w0(4); P1;
179 }
180
181 CCP(0x30);
182
183 pi->delay = d;
184 pi->mode = m;
185 w0(pi->saved_r0);
186 w2(pi->saved_r2);
187
188 return 5;
189}
190
191static void on26_read_block(struct pi_adapter *pi, char *buf, int count)
192{
193 int k, a, b;
194
195 switch (pi->mode) {
196 case 0:
197 w0(1); P1; w0(1); P2; w0(2); P1; w0(0x18); P2; w0(0); P1;
198 udelay(10);
199 for (k = 0; k < count; k++) {
200 w2(6); a = r1();
201 w2(4); b = r1();
202 buf[k] = j44(a, b);
203 }
204 w0(2); P1; w0(8); P2;
205 break;
206 case 1:
207 w0(1); P1; w0(1); P2; w0(2); P1; w0(0x19); P2; w0(0); P1;
208 udelay(10);
209 for (k = 0; k < count / 2; k++) {
210 w2(0x26); buf[2 * k] = r0();
211 w2(0x24); buf[2 * k + 1] = r0();
212 }
213 w0(2); P1; w0(9); P2;
214 break;
215 case 2:
216 w3(1); w3(1); w2(5); w4(1); w2(4);
217 w3(0); w3(0); w2(0x24);
218 udelay(10);
219 for (k = 0; k < count; k++)
220 buf[k] = r4();
221 w2(4);
222 break;
223 case 3:
224 w3(1); w3(1); w2(5); w4(1); w2(4);
225 w3(0); w3(0); w2(0x24);
226 udelay(10);
227 for (k = 0; k < count / 2; k++)
228 ((u16 *)buf)[k] = r4w();
229 w2(4);
230 break;
231 case 4:
232 w3(1); w3(1); w2(5); w4(1); w2(4);
233 w3(0); w3(0); w2(0x24);
234 udelay(10);
235 for (k = 0; k < count / 4; k++)
236 ((u32 *)buf)[k] = r4l();
237 w2(4);
238 break;
239 }
240}
241
242static void on26_write_block(struct pi_adapter *pi, char *buf, int count)
243{
244 int k;
245
246 switch (pi->mode) {
247 case 0:
248 case 1:
249 w0(1); P1; w0(1); P2;
250 w0(2); P1; w0(0x18 + pi->mode); P2; w0(0); P1;
251 udelay(10);
252 for (k = 0; k < count / 2; k++) {
253 w2(5); w0(buf[2 * k]);
254 w2(7); w0(buf[2 * k + 1]);
255 }
256 w2(5); w2(4);
257 w0(2); P1; w0(8 + pi->mode); P2;
258 break;
259 case 2:
260 w3(1); w3(1); w2(5); w4(1); w2(4);
261 w3(0); w3(0); w2(0xc5);
262 udelay(10);
263 for (k = 0; k < count; k++)
264 w4(buf[k]);
265 w2(0xc4);
266 break;
267 case 3:
268 w3(1); w3(1); w2(5); w4(1); w2(4);
269 w3(0); w3(0); w2(0xc5);
270 udelay(10);
271 for (k = 0; k < count / 2; k++)
272 w4w(((u16 *)buf)[k]);
273 w2(0xc4);
274 break;
275 case 4:
276 w3(1); w3(1); w2(5); w4(1); w2(4);
277 w3(0); w3(0); w2(0xc5);
278 udelay(10);
279 for (k = 0; k < count / 4; k++)
280 w4l(((u32 *)buf)[k]);
281 w2(0xc4);
282 break;
283 }
284}
285
286static void on26_log_adapter(struct pi_adapter *pi)
287{
288 char *mode_string[5] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32" };
289
290 dev_info(&pi->dev,
291 "OnSpec 90c26 at 0x%x, mode %d (%s), delay %d\n",
292 pi->port, pi->mode, mode_string[pi->mode], pi->delay);
293}
294
295static struct pi_protocol on26 = {
296 .owner = THIS_MODULE,
297 .name = "on26",
298 .max_mode = 5,
299 .epp_first = 2,
300 .default_delay = 1,
301 .max_units = 1,
302 .write_regr = on26_write_regr,
303 .read_regr = on26_read_regr,
304 .write_block = on26_write_block,
305 .read_block = on26_read_block,
306 .connect = on26_connect,
307 .disconnect = on26_disconnect,
308 .test_port = on26_test_port,
309 .log_adapter = on26_log_adapter,
310};
311
312MODULE_LICENSE("GPL");
313MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>");
314MODULE_DESCRIPTION("Onspec 90c26 parallel port IDE adapter protocol driver");
315module_pata_parport_driver(on26);
316

source code of linux/drivers/ata/pata_parport/on26.c