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