1/* $Id: parport_sunbpp.c,v 1.1.1.1 2008/10/15 03:26:46 james26_jang Exp $
2 * Parallel-port routines for Sun architecture
3 *
4 * Author: Derrick J. Brashear <shadow@dementia.org>
5 *
6 * based on work by:
7 *          Phil Blundell <Philip.Blundell@pobox.com>
8 *          Tim Waugh <tim@cyberelk.demon.co.uk>
9 *	    Jose Renau <renau@acm.org>
10 *          David Campbell <campbell@tirian.che.curtin.edu.au>
11 *          Grant Guenther <grant@torque.net>
12 *          Eddie C. Dost <ecd@skynet.be>
13 *          Stephen Williams (steve@icarus.com)
14 *          Gus Baldauf (gbaldauf@ix.netcom.com)
15 *          Peter Zaitcev
16 *          Tom Dyas
17 */
18
19#include <linux/string.h>
20#include <linux/module.h>
21#include <linux/delay.h>
22#include <linux/errno.h>
23#include <linux/ioport.h>
24#include <linux/kernel.h>
25#include <linux/slab.h>
26#include <linux/init.h>
27
28#include <linux/parport.h>
29
30#include <asm/ptrace.h>
31#include <linux/interrupt.h>
32
33#include <asm/io.h>
34#include <asm/oplib.h>           /* OpenProm Library */
35#include <asm/sbus.h>
36#include <asm/dma.h>             /* BPP uses LSI 64854 for DMA */
37#include <asm/irq.h>
38#include <asm/sunbpp.h>
39
40#undef __SUNBPP_DEBUG
41#ifdef __SUNBPP_DEBUG
42#define dprintk(x) printk x
43#else
44#define dprintk(x)
45#endif
46
47static void parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
48{
49	parport_generic_irq(irq, (struct parport *) dev_id, regs);
50}
51
52static void parport_sunbpp_disable_irq(struct parport *p)
53{
54	struct bpp_regs *regs = (struct bpp_regs *)p->base;
55	u32 tmp;
56
57	tmp = sbus_readl(&regs->p_csr);
58	tmp &= ~DMA_INT_ENAB;
59	sbus_writel(tmp, &regs->p_csr);
60}
61
62static void parport_sunbpp_enable_irq(struct parport *p)
63{
64	struct bpp_regs *regs = (struct bpp_regs *)p->base;
65	u32 tmp;
66
67	tmp = sbus_readl(&regs->p_csr);
68	tmp |= DMA_INT_ENAB;
69	sbus_writel(tmp, &regs->p_csr);
70}
71
72static void parport_sunbpp_write_data(struct parport *p, unsigned char d)
73{
74	struct bpp_regs *regs = (struct bpp_regs *)p->base;
75
76	sbus_writeb(d, &regs->p_dr);
77	dprintk((KERN_DEBUG "wrote 0x%x\n", d));
78}
79
80static unsigned char parport_sunbpp_read_data(struct parport *p)
81{
82	struct bpp_regs *regs = (struct bpp_regs *)p->base;
83
84	return sbus_readb(&regs->p_dr);
85}
86
87
88static unsigned char status_sunbpp_to_pc(struct parport *p)
89{
90	struct bpp_regs *regs = (struct bpp_regs *)p->base;
91	unsigned char bits = 0;
92	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
93	unsigned char value_ir = sbus_readb(&regs->p_ir);
94
95	if (!(value_ir & P_IR_ERR))
96		bits |= PARPORT_STATUS_ERROR;
97	if (!(value_ir & P_IR_SLCT))
98		bits |= PARPORT_STATUS_SELECT;
99	if (!(value_ir & P_IR_PE))
100		bits |= PARPORT_STATUS_PAPEROUT;
101	if (value_tcr & P_TCR_ACK)
102		bits |= PARPORT_STATUS_ACK;
103	if (!(value_tcr & P_TCR_BUSY))
104		bits |= PARPORT_STATUS_BUSY;
105
106	dprintk((KERN_DEBUG "tcr 0x%x ir 0x%x\n", regs->p_tcr, regs->p_ir));
107	dprintk((KERN_DEBUG "read status 0x%x\n", bits));
108	return bits;
109}
110
111static unsigned char control_sunbpp_to_pc(struct parport *p)
112{
113	struct bpp_regs *regs = (struct bpp_regs *)p->base;
114	unsigned char bits = 0;
115	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
116	unsigned char value_or = sbus_readb(&regs->p_or);
117
118	if (!(value_tcr & P_TCR_DS))
119		bits |= PARPORT_CONTROL_STROBE;
120	if (!(value_or & P_OR_AFXN))
121		bits |= PARPORT_CONTROL_AUTOFD;
122	if (!(value_or & P_OR_INIT))
123		bits |= PARPORT_CONTROL_INIT;
124	if (value_or & P_OR_SLCT_IN)
125		bits |= PARPORT_CONTROL_SELECT;
126
127	dprintk((KERN_DEBUG "tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or));
128	dprintk((KERN_DEBUG "read control 0x%x\n", bits));
129	return bits;
130}
131
132static unsigned char parport_sunbpp_read_control(struct parport *p)
133{
134	return control_sunbpp_to_pc(p);
135}
136
137static unsigned char parport_sunbpp_frob_control(struct parport *p,
138						 unsigned char mask,
139						 unsigned char val)
140{
141	struct bpp_regs *regs = (struct bpp_regs *)p->base;
142	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
143	unsigned char value_or = sbus_readb(&regs->p_or);
144
145	dprintk((KERN_DEBUG "frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or));
146	if (mask & PARPORT_CONTROL_STROBE) {
147		if (val & PARPORT_CONTROL_STROBE) {
148			value_tcr &= ~P_TCR_DS;
149		} else {
150			value_tcr |= P_TCR_DS;
151		}
152	}
153	if (mask & PARPORT_CONTROL_AUTOFD) {
154		if (val & PARPORT_CONTROL_AUTOFD) {
155			value_or &= ~P_OR_AFXN;
156		} else {
157			value_or |= P_OR_AFXN;
158		}
159	}
160	if (mask & PARPORT_CONTROL_INIT) {
161		if (val & PARPORT_CONTROL_INIT) {
162			value_or &= ~P_OR_INIT;
163		} else {
164			value_or |= P_OR_INIT;
165		}
166	}
167	if (mask & PARPORT_CONTROL_SELECT) {
168		if (val & PARPORT_CONTROL_SELECT) {
169			value_or |= P_OR_SLCT_IN;
170		} else {
171			value_or &= ~P_OR_SLCT_IN;
172		}
173	}
174
175	sbus_writeb(value_or, &regs->p_or);
176	sbus_writeb(value_tcr, &regs->p_tcr);
177	dprintk((KERN_DEBUG "frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or));
178	return parport_sunbpp_read_control(p);
179}
180
181static void parport_sunbpp_write_control(struct parport *p, unsigned char d)
182{
183	const unsigned char wm = (PARPORT_CONTROL_STROBE |
184				  PARPORT_CONTROL_AUTOFD |
185				  PARPORT_CONTROL_INIT |
186				  PARPORT_CONTROL_SELECT);
187
188	parport_sunbpp_frob_control (p, wm, d & wm);
189}
190
191static unsigned char parport_sunbpp_read_status(struct parport *p)
192{
193	return status_sunbpp_to_pc(p);
194}
195
196static void parport_sunbpp_data_forward (struct parport *p)
197{
198	struct bpp_regs *regs = (struct bpp_regs *)p->base;
199	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
200
201	dprintk((KERN_DEBUG "forward\n"));
202	value_tcr &= ~P_TCR_DIR;
203	sbus_writeb(value_tcr, &regs->p_tcr);
204}
205
206static void parport_sunbpp_data_reverse (struct parport *p)
207{
208	struct bpp_regs *regs = (struct bpp_regs *)p->base;
209	u8 val = sbus_readb(&regs->p_tcr);
210
211	dprintk((KERN_DEBUG "reverse\n"));
212	val |= P_TCR_DIR;
213	sbus_writeb(val, &regs->p_tcr);
214}
215
216static void parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s)
217{
218	s->u.pc.ctr = 0xc;
219	s->u.pc.ecr = 0x0;
220}
221
222static void parport_sunbpp_save_state(struct parport *p, struct parport_state *s)
223{
224	s->u.pc.ctr = parport_sunbpp_read_control(p);
225}
226
227static void parport_sunbpp_restore_state(struct parport *p, struct parport_state *s)
228{
229	parport_sunbpp_write_control(p, s->u.pc.ctr);
230}
231
232static void parport_sunbpp_inc_use_count(void)
233{
234#ifdef MODULE
235	MOD_INC_USE_COUNT;
236#endif
237}
238
239static void parport_sunbpp_dec_use_count(void)
240{
241#ifdef MODULE
242	MOD_DEC_USE_COUNT;
243#endif
244}
245
246static struct parport_operations parport_sunbpp_ops =
247{
248	parport_sunbpp_write_data,
249	parport_sunbpp_read_data,
250
251	parport_sunbpp_write_control,
252	parport_sunbpp_read_control,
253	parport_sunbpp_frob_control,
254
255	parport_sunbpp_read_status,
256
257	parport_sunbpp_enable_irq,
258        parport_sunbpp_disable_irq,
259
260        parport_sunbpp_data_forward,
261        parport_sunbpp_data_reverse,
262
263        parport_sunbpp_init_state,
264        parport_sunbpp_save_state,
265        parport_sunbpp_restore_state,
266
267        parport_sunbpp_inc_use_count,
268        parport_sunbpp_dec_use_count,
269
270        parport_ieee1284_epp_write_data,
271        parport_ieee1284_epp_read_data,
272        parport_ieee1284_epp_write_addr,
273        parport_ieee1284_epp_read_addr,
274
275        parport_ieee1284_ecp_write_data,
276        parport_ieee1284_ecp_read_data,
277        parport_ieee1284_ecp_write_addr,
278
279        parport_ieee1284_write_compat,
280        parport_ieee1284_read_nibble,
281        parport_ieee1284_read_byte,
282};
283
284static int __init init_one_port(struct sbus_dev *sdev)
285{
286	struct parport *p;
287	/* at least in theory there may be a "we don't dma" case */
288	struct parport_operations *ops;
289	unsigned long base;
290	int irq, dma, err, size;
291	struct bpp_regs *regs;
292	unsigned char value_tcr;
293
294	dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev));
295	irq = sdev->irqs[0];
296	base = sbus_ioremap(&sdev->resource[0], 0,
297			    sdev->reg_addrs[0].reg_size,
298			    "sunbpp");
299	size = sdev->reg_addrs[0].reg_size;
300	dma = PARPORT_DMA_NONE;
301
302	dprintk(("alloc(ppops), "));
303	ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
304        if (!ops) {
305		sbus_iounmap(base, size);
306		return 0;
307        }
308
309        memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
310
311	dprintk(("register_port\n"));
312	if (!(p = parport_register_port(base, irq, dma, ops))) {
313		kfree(ops);
314		sbus_iounmap(base, size);
315		return 0;
316	}
317
318	p->size = size;
319
320	dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ",
321		p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p));
322	if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
323			       SA_SHIRQ, p->name, p)) != 0) {
324		dprintk(("ERROR %d\n", err));
325		parport_unregister_port(p);
326		kfree(ops);
327		sbus_iounmap(base, size);
328		return err;
329	} else {
330		dprintk(("OK\n"));
331		parport_sunbpp_enable_irq(p);
332	}
333
334	regs = (struct bpp_regs *)p->base;
335	dprintk((KERN_DEBUG "forward\n"));
336	value_tcr = sbus_readb(&regs->p_tcr);
337	value_tcr &= ~P_TCR_DIR;
338	sbus_writeb(value_tcr, &regs->p_tcr);
339
340	printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
341	parport_proc_register(p);
342	parport_announce_port (p);
343
344	return 1;
345}
346
347EXPORT_NO_SYMBOLS;
348
349#ifdef MODULE
350int init_module(void)
351#else
352int __init parport_sunbpp_init(void)
353#endif
354{
355        struct sbus_bus *sbus;
356        struct sbus_dev *sdev;
357	int count = 0;
358
359	for_each_sbus(sbus) {
360		for_each_sbusdev(sdev, sbus) {
361			if (!strcmp(sdev->prom_name, "SUNW,bpp"))
362				count += init_one_port(sdev);
363		}
364	}
365	return count ? 0 : -ENODEV;
366}
367
368#ifdef MODULE
369MODULE_AUTHOR("Derrick J Brashear");
370MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
371MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
372
373void
374cleanup_module(void)
375{
376	struct parport *p = parport_enumerate();
377
378	while (p) {
379		struct parport *next = p->next;
380
381		if (1/*p->modes & PARPORT_MODE_PCSPP*/) {
382			struct parport_operations *ops = p->ops;
383
384			if (p->irq != PARPORT_IRQ_NONE) {
385				parport_sunbpp_disable_irq(p);
386				free_irq(p->irq, p);
387			}
388			sbus_iounmap(p->base, p->size);
389			parport_proc_unregister(p);
390			parport_unregister_port(p);
391			kfree (ops);
392		}
393		p = next;
394	}
395}
396#endif
397