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
37static 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
60static 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
69static 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
82static 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
89static 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
107static 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
119static 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
128static 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
144MODULE_LICENSE("GPL");
145MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>");
146MODULE_DESCRIPTION("Onspec 90c20 parallel port IDE adapter protocol driver");
147module_pata_parport_driver(on20);
148

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