1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* Low-level parallel port routines for the Atari builtin port
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Based on parport_amiga.c.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * The built-in Atari parallel port provides one port at a fixed address
9*4882a593Smuzhiyun * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
10*4882a593Smuzhiyun * and 1 input status line (BUSY) able to cause an interrupt.
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/parport.h>
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <asm/setup.h>
18*4882a593Smuzhiyun #include <asm/atarihw.h>
19*4882a593Smuzhiyun #include <asm/irq.h>
20*4882a593Smuzhiyun #include <asm/atariints.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static struct parport *this_port;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun static unsigned char
parport_atari_read_data(struct parport * p)25*4882a593Smuzhiyun parport_atari_read_data(struct parport *p)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun unsigned long flags;
28*4882a593Smuzhiyun unsigned char data;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun local_irq_save(flags);
31*4882a593Smuzhiyun sound_ym.rd_data_reg_sel = 15;
32*4882a593Smuzhiyun data = sound_ym.rd_data_reg_sel;
33*4882a593Smuzhiyun local_irq_restore(flags);
34*4882a593Smuzhiyun return data;
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun static void
parport_atari_write_data(struct parport * p,unsigned char data)38*4882a593Smuzhiyun parport_atari_write_data(struct parport *p, unsigned char data)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun unsigned long flags;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun local_irq_save(flags);
43*4882a593Smuzhiyun sound_ym.rd_data_reg_sel = 15;
44*4882a593Smuzhiyun sound_ym.wd_data = data;
45*4882a593Smuzhiyun local_irq_restore(flags);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun static unsigned char
parport_atari_read_control(struct parport * p)49*4882a593Smuzhiyun parport_atari_read_control(struct parport *p)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun unsigned long flags;
52*4882a593Smuzhiyun unsigned char control = 0;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun local_irq_save(flags);
55*4882a593Smuzhiyun sound_ym.rd_data_reg_sel = 14;
56*4882a593Smuzhiyun if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
57*4882a593Smuzhiyun control = PARPORT_CONTROL_STROBE;
58*4882a593Smuzhiyun local_irq_restore(flags);
59*4882a593Smuzhiyun return control;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static void
parport_atari_write_control(struct parport * p,unsigned char control)63*4882a593Smuzhiyun parport_atari_write_control(struct parport *p, unsigned char control)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun unsigned long flags;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun local_irq_save(flags);
68*4882a593Smuzhiyun sound_ym.rd_data_reg_sel = 14;
69*4882a593Smuzhiyun if (control & PARPORT_CONTROL_STROBE)
70*4882a593Smuzhiyun sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
71*4882a593Smuzhiyun else
72*4882a593Smuzhiyun sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
73*4882a593Smuzhiyun local_irq_restore(flags);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun static unsigned char
parport_atari_frob_control(struct parport * p,unsigned char mask,unsigned char val)77*4882a593Smuzhiyun parport_atari_frob_control(struct parport *p, unsigned char mask,
78*4882a593Smuzhiyun unsigned char val)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun unsigned char old = parport_atari_read_control(p);
81*4882a593Smuzhiyun parport_atari_write_control(p, (old & ~mask) ^ val);
82*4882a593Smuzhiyun return old;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun static unsigned char
parport_atari_read_status(struct parport * p)86*4882a593Smuzhiyun parport_atari_read_status(struct parport *p)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun return ((st_mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
89*4882a593Smuzhiyun PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static void
parport_atari_init_state(struct pardevice * d,struct parport_state * s)93*4882a593Smuzhiyun parport_atari_init_state(struct pardevice *d, struct parport_state *s)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun static void
parport_atari_save_state(struct parport * p,struct parport_state * s)98*4882a593Smuzhiyun parport_atari_save_state(struct parport *p, struct parport_state *s)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun static void
parport_atari_restore_state(struct parport * p,struct parport_state * s)103*4882a593Smuzhiyun parport_atari_restore_state(struct parport *p, struct parport_state *s)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun static void
parport_atari_enable_irq(struct parport * p)108*4882a593Smuzhiyun parport_atari_enable_irq(struct parport *p)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun enable_irq(IRQ_MFP_BUSY);
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun static void
parport_atari_disable_irq(struct parport * p)114*4882a593Smuzhiyun parport_atari_disable_irq(struct parport *p)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun disable_irq(IRQ_MFP_BUSY);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun static void
parport_atari_data_forward(struct parport * p)120*4882a593Smuzhiyun parport_atari_data_forward(struct parport *p)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun unsigned long flags;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun local_irq_save(flags);
125*4882a593Smuzhiyun /* Soundchip port B as output. */
126*4882a593Smuzhiyun sound_ym.rd_data_reg_sel = 7;
127*4882a593Smuzhiyun sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x40;
128*4882a593Smuzhiyun local_irq_restore(flags);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun static void
parport_atari_data_reverse(struct parport * p)132*4882a593Smuzhiyun parport_atari_data_reverse(struct parport *p)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun static struct parport_operations parport_atari_ops = {
137*4882a593Smuzhiyun .write_data = parport_atari_write_data,
138*4882a593Smuzhiyun .read_data = parport_atari_read_data,
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun .write_control = parport_atari_write_control,
141*4882a593Smuzhiyun .read_control = parport_atari_read_control,
142*4882a593Smuzhiyun .frob_control = parport_atari_frob_control,
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun .read_status = parport_atari_read_status,
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun .enable_irq = parport_atari_enable_irq,
147*4882a593Smuzhiyun .disable_irq = parport_atari_disable_irq,
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun .data_forward = parport_atari_data_forward,
150*4882a593Smuzhiyun .data_reverse = parport_atari_data_reverse,
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun .init_state = parport_atari_init_state,
153*4882a593Smuzhiyun .save_state = parport_atari_save_state,
154*4882a593Smuzhiyun .restore_state = parport_atari_restore_state,
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun .epp_write_data = parport_ieee1284_epp_write_data,
157*4882a593Smuzhiyun .epp_read_data = parport_ieee1284_epp_read_data,
158*4882a593Smuzhiyun .epp_write_addr = parport_ieee1284_epp_write_addr,
159*4882a593Smuzhiyun .epp_read_addr = parport_ieee1284_epp_read_addr,
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun .ecp_write_data = parport_ieee1284_ecp_write_data,
162*4882a593Smuzhiyun .ecp_read_data = parport_ieee1284_ecp_read_data,
163*4882a593Smuzhiyun .ecp_write_addr = parport_ieee1284_ecp_write_addr,
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun .compat_write_data = parport_ieee1284_write_compat,
166*4882a593Smuzhiyun .nibble_read_data = parport_ieee1284_read_nibble,
167*4882a593Smuzhiyun .byte_read_data = parport_ieee1284_read_byte,
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun .owner = THIS_MODULE,
170*4882a593Smuzhiyun };
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun
parport_atari_init(void)173*4882a593Smuzhiyun static int __init parport_atari_init(void)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun struct parport *p;
176*4882a593Smuzhiyun unsigned long flags;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun if (MACH_IS_ATARI) {
179*4882a593Smuzhiyun local_irq_save(flags);
180*4882a593Smuzhiyun /* Soundchip port A/B as output. */
181*4882a593Smuzhiyun sound_ym.rd_data_reg_sel = 7;
182*4882a593Smuzhiyun sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
183*4882a593Smuzhiyun /* STROBE high. */
184*4882a593Smuzhiyun sound_ym.rd_data_reg_sel = 14;
185*4882a593Smuzhiyun sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
186*4882a593Smuzhiyun local_irq_restore(flags);
187*4882a593Smuzhiyun /* MFP port I0 as input. */
188*4882a593Smuzhiyun st_mfp.data_dir &= ~1;
189*4882a593Smuzhiyun /* MFP port I0 interrupt on high->low edge. */
190*4882a593Smuzhiyun st_mfp.active_edge &= ~1;
191*4882a593Smuzhiyun p = parport_register_port((unsigned long)&sound_ym.wd_data,
192*4882a593Smuzhiyun IRQ_MFP_BUSY, PARPORT_DMA_NONE,
193*4882a593Smuzhiyun &parport_atari_ops);
194*4882a593Smuzhiyun if (!p)
195*4882a593Smuzhiyun return -ENODEV;
196*4882a593Smuzhiyun if (request_irq(IRQ_MFP_BUSY, parport_irq_handler, 0, p->name,
197*4882a593Smuzhiyun p)) {
198*4882a593Smuzhiyun parport_put_port (p);
199*4882a593Smuzhiyun return -ENODEV;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun this_port = p;
203*4882a593Smuzhiyun pr_info("%s: Atari built-in port using irq\n", p->name);
204*4882a593Smuzhiyun parport_announce_port (p);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun return 0;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun return -ENODEV;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
parport_atari_exit(void)211*4882a593Smuzhiyun static void __exit parport_atari_exit(void)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun parport_remove_port(this_port);
214*4882a593Smuzhiyun if (this_port->irq != PARPORT_IRQ_NONE)
215*4882a593Smuzhiyun free_irq(IRQ_MFP_BUSY, this_port);
216*4882a593Smuzhiyun parport_put_port(this_port);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun MODULE_AUTHOR("Andreas Schwab");
220*4882a593Smuzhiyun MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
221*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
222*4882a593Smuzhiyun MODULE_LICENSE("GPL");
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun module_init(parport_atari_init)
225*4882a593Smuzhiyun module_exit(parport_atari_exit)
226