1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * (c) 1996-1998 Grant R. Guenther <grant@torque.net>
4 *
5 * on20.c is a low-level protocol driver for the
6 * Onspec 90c20 parallel to IDE adapter.
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 #define op(f) \
19 do { \
20 w2(4); w0(f); w2(5); w2(0xd); \
21 w2(5); w2(0xd); w2(5); w2(4); \
22 } while (0)
23
24 #define vl(v) \
25 do { \
26 w2(4); w0(v); w2(5); \
27 w2(7); w2(5); w2(4); \
28 } while (0)
29
30 #define j44(a, b) (((a >> 4) & 0x0f) | (b & 0xf0))
31
32 /*
33 * cont = 0 - access the IDE register file
34 * cont = 1 - access the IDE command set
35 */
36
on20_read_regr(struct pi_adapter * pi,int cont,int regr)37 static int on20_read_regr(struct pi_adapter *pi, int cont, int regr)
38 {
39 int h, l, r;
40
41 r = (regr << 2) + 1 + cont;
42
43 op(1); vl(r); op(0);
44
45 switch (pi->mode) {
46 case 0:
47 w2(4); w2(6); l = r1();
48 w2(4); w2(6); h = r1();
49 w2(4); w2(6); w2(4); w2(6); w2(4);
50 return j44(l, h);
51 case 1:
52 w2(4); w2(0x26); r = r0();
53 w2(4); w2(0x26); w2(4);
54 return r;
55 }
56
57 return -1;
58 }
59
on20_write_regr(struct pi_adapter * pi,int cont,int regr,int val)60 static void on20_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
61 {
62 int r = (regr << 2) + 1 + cont;
63
64 op(1); vl(r);
65 op(0); vl(val);
66 op(0); vl(val);
67 }
68
on20_connect(struct pi_adapter * pi)69 static void on20_connect(struct pi_adapter *pi)
70 {
71 pi->saved_r0 = r0();
72 pi->saved_r2 = r2();
73
74 w2(4); w0(0); w2(0xc); w2(4); w2(6); w2(4); w2(6); w2(4);
75 if (pi->mode) {
76 op(2); vl(8); op(2); vl(9);
77 } else {
78 op(2); vl(0); op(2); vl(8);
79 }
80 }
81
on20_disconnect(struct pi_adapter * pi)82 static void on20_disconnect(struct pi_adapter *pi)
83 {
84 w2(4); w0(7); w2(4); w2(0xc); w2(4);
85 w0(pi->saved_r0);
86 w2(pi->saved_r2);
87 }
88
on20_read_block(struct pi_adapter * pi,char * buf,int count)89 static void on20_read_block(struct pi_adapter *pi, char *buf, int count)
90 {
91 int k, l, h;
92
93 op(1); vl(1); op(0);
94
95 for (k = 0; k < count; k++) {
96 if (pi->mode) {
97 w2(4); w2(0x26); buf[k] = r0();
98 } else {
99 w2(6); l = r1(); w2(4);
100 w2(6); h = r1(); w2(4);
101 buf[k] = j44(l, h);
102 }
103 }
104 w2(4);
105 }
106
on20_write_block(struct pi_adapter * pi,char * buf,int count)107 static void on20_write_block(struct pi_adapter *pi, char *buf, int count)
108 {
109 int k;
110
111 op(1); vl(1); op(0);
112
113 for (k = 0; k < count; k++) {
114 w2(5); w0(buf[k]); w2(7);
115 }
116 w2(4);
117 }
118
on20_log_adapter(struct pi_adapter * pi)119 static void on20_log_adapter(struct pi_adapter *pi)
120 {
121 char *mode_string[2] = { "4-bit", "8-bit" };
122
123 dev_info(&pi->dev,
124 "OnSpec 90c20 at 0x%x, mode %d (%s), delay %d\n",
125 pi->port, pi->mode, mode_string[pi->mode], pi->delay);
126 }
127
128 static struct pi_protocol on20 = {
129 .owner = THIS_MODULE,
130 .name = "on20",
131 .max_mode = 2,
132 .epp_first = 2,
133 .default_delay = 1,
134 .max_units = 1,
135 .write_regr = on20_write_regr,
136 .read_regr = on20_read_regr,
137 .write_block = on20_write_block,
138 .read_block = on20_read_block,
139 .connect = on20_connect,
140 .disconnect = on20_disconnect,
141 .log_adapter = on20_log_adapter,
142 };
143
144 MODULE_LICENSE("GPL");
145 MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>");
146 MODULE_DESCRIPTION("Onspec 90c20 parallel port IDE adapter protocol driver");
147 module_pata_parport_driver(on20);
148