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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |