Blame view

drivers/parport/parport_sunbpp.c 10.2 KB
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
1
  /* parport_sunbpp.c: Parallel-port routines for SBUS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   * 
   * Author: Derrick J. Brashear <shadow@dementia.org>
   *
   * based on work by:
   *          Phil Blundell <philb@gnu.org>
   *          Tim Waugh <tim@cyberelk.demon.co.uk>
   *	    Jose Renau <renau@acm.org>
   *          David Campbell <campbell@tirian.che.curtin.edu.au>
   *          Grant Guenther <grant@torque.net>
   *          Eddie C. Dost <ecd@skynet.be>
   *          Stephen Williams (steve@icarus.com)
   *          Gus Baldauf (gbaldauf@ix.netcom.com)
   *          Peter Zaitcev
   *          Tom Dyas
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
16
17
18
   *
   * Updated to new SBUS device framework: David S. Miller <davem@davemloft.net>
   * 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
23
24
25
26
27
28
   */
  
  #include <linux/string.h>
  #include <linux/module.h>
  #include <linux/delay.h>
  #include <linux/errno.h>
  #include <linux/ioport.h>
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/init.h>
27167e0e6   David S. Miller   parport_sunbpp: C...
29
30
  #include <linux/of.h>
  #include <linux/of_device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
36
37
38
  
  #include <linux/parport.h>
  
  #include <asm/ptrace.h>
  #include <linux/interrupt.h>
  
  #include <asm/io.h>
  #include <asm/oplib.h>           /* OpenProm Library */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
44
45
46
47
48
  #include <asm/dma.h>             /* BPP uses LSI 64854 for DMA */
  #include <asm/irq.h>
  #include <asm/sunbpp.h>
  
  #undef __SUNBPP_DEBUG
  #ifdef __SUNBPP_DEBUG
  #define dprintk(x) printk x
  #else
  #define dprintk(x)
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  static void parport_sunbpp_disable_irq(struct parport *p)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  	u32 tmp;
  
  	tmp = sbus_readl(&regs->p_csr);
  	tmp &= ~DMA_INT_ENAB;
  	sbus_writel(tmp, &regs->p_csr);
  }
  
  static void parport_sunbpp_enable_irq(struct parport *p)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  	u32 tmp;
  
  	tmp = sbus_readl(&regs->p_csr);
  	tmp |= DMA_INT_ENAB;
  	sbus_writel(tmp, &regs->p_csr);
  }
  
  static void parport_sunbpp_write_data(struct parport *p, unsigned char d)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  
  	sbus_writeb(d, &regs->p_dr);
  	dprintk((KERN_DEBUG "wrote 0x%x
  ", d));
  }
  
  static unsigned char parport_sunbpp_read_data(struct parport *p)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  
  	return sbus_readb(&regs->p_dr);
  }
  
  #if 0
  static void control_pc_to_sunbpp(struct parport *p, unsigned char status)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
  	unsigned char value_or = sbus_readb(&regs->p_or);
  
  	if (status & PARPORT_CONTROL_STROBE) 
  		value_tcr |= P_TCR_DS;
  	if (status & PARPORT_CONTROL_AUTOFD) 
  		value_or |= P_OR_AFXN;
  	if (status & PARPORT_CONTROL_INIT) 
  		value_or |= P_OR_INIT;
  	if (status & PARPORT_CONTROL_SELECT) 
  		value_or |= P_OR_SLCT_IN;
  
  	sbus_writeb(value_or, &regs->p_or);
  	sbus_writeb(value_tcr, &regs->p_tcr);
  }
  #endif
  
  static unsigned char status_sunbpp_to_pc(struct parport *p)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  	unsigned char bits = 0;
  	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
  	unsigned char value_ir = sbus_readb(&regs->p_ir);
  
  	if (!(value_ir & P_IR_ERR))
  		bits |= PARPORT_STATUS_ERROR;
  	if (!(value_ir & P_IR_SLCT))
  		bits |= PARPORT_STATUS_SELECT;
  	if (!(value_ir & P_IR_PE))
  		bits |= PARPORT_STATUS_PAPEROUT;
  	if (value_tcr & P_TCR_ACK)
  		bits |= PARPORT_STATUS_ACK;
  	if (!(value_tcr & P_TCR_BUSY))
  		bits |= PARPORT_STATUS_BUSY;
5a68b2e34   David S. Miller   [PARPORT] SUNBPP:...
123
124
  	dprintk((KERN_DEBUG "tcr 0x%x ir 0x%x
  ", value_tcr, value_ir));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  	dprintk((KERN_DEBUG "read status 0x%x
  ", bits));
  	return bits;
  }
  
  static unsigned char control_sunbpp_to_pc(struct parport *p)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  	unsigned char bits = 0;
  	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
  	unsigned char value_or = sbus_readb(&regs->p_or);
  
  	if (!(value_tcr & P_TCR_DS))
  		bits |= PARPORT_CONTROL_STROBE;
  	if (!(value_or & P_OR_AFXN))
  		bits |= PARPORT_CONTROL_AUTOFD;
  	if (!(value_or & P_OR_INIT))
  		bits |= PARPORT_CONTROL_INIT;
  	if (value_or & P_OR_SLCT_IN)
  		bits |= PARPORT_CONTROL_SELECT;
5a68b2e34   David S. Miller   [PARPORT] SUNBPP:...
145
146
  	dprintk((KERN_DEBUG "tcr 0x%x or 0x%x
  ", value_tcr, value_or));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  	dprintk((KERN_DEBUG "read control 0x%x
  ", bits));
  	return bits;
  }
  
  static unsigned char parport_sunbpp_read_control(struct parport *p)
  {
  	return control_sunbpp_to_pc(p);
  }
  
  static unsigned char parport_sunbpp_frob_control(struct parport *p,
  						 unsigned char mask,
  						 unsigned char val)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
  	unsigned char value_or = sbus_readb(&regs->p_or);
5a68b2e34   David S. Miller   [PARPORT] SUNBPP:...
164
165
166
  	dprintk((KERN_DEBUG "frob1: tcr 0x%x or 0x%x
  ",
  		 value_tcr, value_or));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  	if (mask & PARPORT_CONTROL_STROBE) {
  		if (val & PARPORT_CONTROL_STROBE) {
  			value_tcr &= ~P_TCR_DS;
  		} else {
  			value_tcr |= P_TCR_DS;
  		}
  	}
  	if (mask & PARPORT_CONTROL_AUTOFD) {
  		if (val & PARPORT_CONTROL_AUTOFD) {
  			value_or &= ~P_OR_AFXN;
  		} else {
  			value_or |= P_OR_AFXN;
  		}
  	}
  	if (mask & PARPORT_CONTROL_INIT) {
  		if (val & PARPORT_CONTROL_INIT) {
  			value_or &= ~P_OR_INIT;
  		} else {
  			value_or |= P_OR_INIT;
  		}
  	}
  	if (mask & PARPORT_CONTROL_SELECT) {
  		if (val & PARPORT_CONTROL_SELECT) {
  			value_or |= P_OR_SLCT_IN;
  		} else {
  			value_or &= ~P_OR_SLCT_IN;
  		}
  	}
  
  	sbus_writeb(value_or, &regs->p_or);
  	sbus_writeb(value_tcr, &regs->p_tcr);
5a68b2e34   David S. Miller   [PARPORT] SUNBPP:...
198
199
200
  	dprintk((KERN_DEBUG "frob2: tcr 0x%x or 0x%x
  ",
  		 value_tcr, value_or));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
  	return parport_sunbpp_read_control(p);
  }
  
  static void parport_sunbpp_write_control(struct parport *p, unsigned char d)
  {
  	const unsigned char wm = (PARPORT_CONTROL_STROBE |
  				  PARPORT_CONTROL_AUTOFD |
  				  PARPORT_CONTROL_INIT |
  				  PARPORT_CONTROL_SELECT);
  
  	parport_sunbpp_frob_control (p, wm, d & wm);
  }
  
  static unsigned char parport_sunbpp_read_status(struct parport *p)
  {
  	return status_sunbpp_to_pc(p);
  }
  
  static void parport_sunbpp_data_forward (struct parport *p)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  	unsigned char value_tcr = sbus_readb(&regs->p_tcr);
  
  	dprintk((KERN_DEBUG "forward
  "));
  	value_tcr &= ~P_TCR_DIR;
  	sbus_writeb(value_tcr, &regs->p_tcr);
  }
  
  static void parport_sunbpp_data_reverse (struct parport *p)
  {
  	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
  	u8 val = sbus_readb(&regs->p_tcr);
  
  	dprintk((KERN_DEBUG "reverse
  "));
  	val |= P_TCR_DIR;
  	sbus_writeb(val, &regs->p_tcr);
  }
  
  static void parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s)
  {
  	s->u.pc.ctr = 0xc;
  	s->u.pc.ecr = 0x0;
  }
  
  static void parport_sunbpp_save_state(struct parport *p, struct parport_state *s)
  {
  	s->u.pc.ctr = parport_sunbpp_read_control(p);
  }
  
  static void parport_sunbpp_restore_state(struct parport *p, struct parport_state *s)
  {
  	parport_sunbpp_write_control(p, s->u.pc.ctr);
  }
  
  static struct parport_operations parport_sunbpp_ops = 
  {
  	.write_data	= parport_sunbpp_write_data,
  	.read_data	= parport_sunbpp_read_data,
  
  	.write_control	= parport_sunbpp_write_control,
  	.read_control	= parport_sunbpp_read_control,
  	.frob_control	= parport_sunbpp_frob_control,
  
  	.read_status	= parport_sunbpp_read_status,
  
  	.enable_irq	= parport_sunbpp_enable_irq,
  	.disable_irq	= parport_sunbpp_disable_irq,
  
  	.data_forward	= parport_sunbpp_data_forward,
  	.data_reverse	= parport_sunbpp_data_reverse,
  
  	.init_state	= parport_sunbpp_init_state,
  	.save_state	= parport_sunbpp_save_state,
  	.restore_state	= parport_sunbpp_restore_state,
  
  	.epp_write_data	= parport_ieee1284_epp_write_data,
  	.epp_read_data	= parport_ieee1284_epp_read_data,
  	.epp_write_addr	= parport_ieee1284_epp_write_addr,
  	.epp_read_addr	= parport_ieee1284_epp_read_addr,
  
  	.ecp_write_data	= parport_ieee1284_ecp_write_data,
  	.ecp_read_data	= parport_ieee1284_ecp_read_data,
  	.ecp_write_addr	= parport_ieee1284_ecp_write_addr,
  
  	.compat_write_data	= parport_ieee1284_write_compat,
  	.nibble_read_data	= parport_ieee1284_read_nibble,
  	.byte_read_data		= parport_ieee1284_read_byte,
  
  	.owner		= THIS_MODULE,
  };
2dc115813   Grant Likely   of/device: Replac...
293
  static int __devinit bpp_probe(struct platform_device *op, const struct of_device_id *match)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  	struct parport_operations *ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  	struct bpp_regs __iomem *regs;
27167e0e6   David S. Miller   parport_sunbpp: C...
297
  	int irq, dma, err = 0, size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  	unsigned char value_tcr;
27167e0e6   David S. Miller   parport_sunbpp: C...
299
300
  	void __iomem *base;
  	struct parport *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301

1636f8ac2   Grant Likely   sparc/of: Move of...
302
  	irq = op->archdata.irqs[0];
27167e0e6   David S. Miller   parport_sunbpp: C...
303
304
305
  	base = of_ioremap(&op->resource[0], 0,
  			  resource_size(&op->resource[0]),
  			  "sunbpp");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  	if (!base)
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
307
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308

27167e0e6   David S. Miller   parport_sunbpp: C...
309
  	size = resource_size(&op->resource[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  	dma = PARPORT_DMA_NONE;
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
311
  	ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
          if (!ops)
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
313
  		goto out_unmap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314

27167e0e6   David S. Miller   parport_sunbpp: C...
315
          memcpy (ops, &parport_sunbpp_ops, sizeof(struct parport_operations));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
  
  	dprintk(("register_port
  "));
  	if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
320
  		goto out_free_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
  
  	p->size = size;
27167e0e6   David S. Miller   parport_sunbpp: C...
323
  	p->dev = &op->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324

3f2e40df0   Jeff Garzik   [PARPORT] Consoli...
325
  	if ((err = request_irq(p->irq, parport_irq_handler,
dace14537   Thomas Gleixner   [PATCH] irq-flags...
326
  			       IRQF_SHARED, p->name, p)) != 0) {
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
327
  		goto out_put_port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
  	}
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
329

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
  	parport_sunbpp_enable_irq(p);
  
  	regs = (struct bpp_regs __iomem *)p->base;
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
333

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
338
339
  	value_tcr = sbus_readb(&regs->p_tcr);
  	value_tcr &= ~P_TCR_DIR;
  	sbus_writeb(value_tcr, &regs->p_tcr);
  
  	printk(KERN_INFO "%s: sunbpp at 0x%lx
  ", p->name, p->base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340

27167e0e6   David S. Miller   parport_sunbpp: C...
341
  	dev_set_drvdata(&op->dev, p);
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
342
343
344
345
  
  	parport_announce_port(p);
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346

4f62d158a   David S. Miller   [PARPORT] sunbpp:...
347
  out_put_port:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
  	parport_put_port(p);
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
349
350
  
  out_free_ops:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  	kfree(ops);
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
352
353
  
  out_unmap:
27167e0e6   David S. Miller   parport_sunbpp: C...
354
  	of_iounmap(&op->resource[0], base, size);
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
355

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
  	return err;
  }
2dc115813   Grant Likely   of/device: Replac...
358
  static int __devexit bpp_remove(struct platform_device *op)
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
359
  {
27167e0e6   David S. Miller   parport_sunbpp: C...
360
  	struct parport *p = dev_get_drvdata(&op->dev);
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
361
362
363
364
365
366
367
  	struct parport_operations *ops = p->ops;
  
  	parport_remove_port(p);
  
  	if (p->irq != PARPORT_IRQ_NONE) {
  		parport_sunbpp_disable_irq(p);
  		free_irq(p->irq, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  	}
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
369

27167e0e6   David S. Miller   parport_sunbpp: C...
370
  	of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size);
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
371
372
  	parport_put_port(p);
  	kfree(ops);
27167e0e6   David S. Miller   parport_sunbpp: C...
373
  	dev_set_drvdata(&op->dev, NULL);
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
374
375
376
  
  	return 0;
  }
fd098316e   David S. Miller   sparc: Annotate o...
377
  static const struct of_device_id bpp_match[] = {
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
378
379
380
381
382
  	{
  		.name = "SUNW,bpp",
  	},
  	{},
  };
09ec43147   David S. Miller   [PARPORT] sunbpp:...
383
  MODULE_DEVICE_TABLE(of, bpp_match);
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
384
385
  
  static struct of_platform_driver bpp_sbus_driver = {
4018294b5   Grant Likely   of: Remove duplic...
386
387
388
389
390
  	.driver = {
  		.name = "bpp",
  		.owner = THIS_MODULE,
  		.of_match_table = bpp_match,
  	},
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
391
392
393
394
395
396
  	.probe		= bpp_probe,
  	.remove		= __devexit_p(bpp_remove),
  };
  
  static int __init parport_sunbpp_init(void)
  {
1ab1d63a8   Grant Likely   of/platform: remo...
397
  	return of_register_platform_driver(&bpp_sbus_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
401
  }
  
  static void __exit parport_sunbpp_exit(void)
  {
1ab1d63a8   Grant Likely   of/platform: remo...
402
  	of_unregister_platform_driver(&bpp_sbus_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
406
407
  }
  
  MODULE_AUTHOR("Derrick J Brashear");
  MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
  MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
4f62d158a   David S. Miller   [PARPORT] sunbpp:...
408
  MODULE_VERSION("2.0");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
  MODULE_LICENSE("GPL");
  
  module_init(parport_sunbpp_init)
  module_exit(parport_sunbpp_exit)