brintos

brintos / linux-shallow public Read only

0
0
Text · 9.3 KiB · 949236a Raw
380 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* parport_sunbpp.c: Parallel-port routines for SBUS3 * 4 * Author: Derrick J. Brashear <shadow@dementia.org>5 *6 * based on work by:7 *          Phil Blundell <philb@gnu.org>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 Zaitcev16 *          Tom Dyas17 *18 * Updated to new SBUS device framework: David S. Miller <davem@davemloft.net>19 * 20 */21 22#include <linux/string.h>23#include <linux/module.h>24#include <linux/delay.h>25#include <linux/errno.h>26#include <linux/ioport.h>27#include <linux/kernel.h>28#include <linux/slab.h>29#include <linux/init.h>30#include <linux/of.h>31#include <linux/platform_device.h>32 33#include <linux/parport.h>34 35#include <asm/ptrace.h>36#include <linux/interrupt.h>37 38#include <asm/io.h>39#include <asm/oplib.h>           /* OpenProm Library */40#include <asm/dma.h>             /* BPP uses LSI 64854 for DMA */41#include <asm/irq.h>42#include <asm/sunbpp.h>43 44#undef __SUNBPP_DEBUG45#ifdef __SUNBPP_DEBUG46#define dprintk(x) printk x47#else48#define dprintk(x)49#endif50 51static void parport_sunbpp_disable_irq(struct parport *p)52{53	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;54	u32 tmp;55 56	tmp = sbus_readl(&regs->p_csr);57	tmp &= ~DMA_INT_ENAB;58	sbus_writel(tmp, &regs->p_csr);59}60 61static void parport_sunbpp_enable_irq(struct parport *p)62{63	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;64	u32 tmp;65 66	tmp = sbus_readl(&regs->p_csr);67	tmp |= DMA_INT_ENAB;68	sbus_writel(tmp, &regs->p_csr);69}70 71static void parport_sunbpp_write_data(struct parport *p, unsigned char d)72{73	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;74 75	sbus_writeb(d, &regs->p_dr);76	dprintk((KERN_DEBUG "wrote 0x%x\n", d));77}78 79static unsigned char parport_sunbpp_read_data(struct parport *p)80{81	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;82 83	return sbus_readb(&regs->p_dr);84}85 86static unsigned char status_sunbpp_to_pc(struct parport *p)87{88	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;89	unsigned char bits = 0;90	unsigned char value_tcr = sbus_readb(&regs->p_tcr);91	unsigned char value_ir = sbus_readb(&regs->p_ir);92 93	if (!(value_ir & P_IR_ERR))94		bits |= PARPORT_STATUS_ERROR;95	if (!(value_ir & P_IR_SLCT))96		bits |= PARPORT_STATUS_SELECT;97	if (!(value_ir & P_IR_PE))98		bits |= PARPORT_STATUS_PAPEROUT;99	if (value_tcr & P_TCR_ACK)100		bits |= PARPORT_STATUS_ACK;101	if (!(value_tcr & P_TCR_BUSY))102		bits |= PARPORT_STATUS_BUSY;103 104	dprintk((KERN_DEBUG "tcr 0x%x ir 0x%x\n", value_tcr, value_ir));105	dprintk((KERN_DEBUG "read status 0x%x\n", bits));106	return bits;107}108 109static unsigned char control_sunbpp_to_pc(struct parport *p)110{111	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;112	unsigned char bits = 0;113	unsigned char value_tcr = sbus_readb(&regs->p_tcr);114	unsigned char value_or = sbus_readb(&regs->p_or);115 116	if (!(value_tcr & P_TCR_DS))117		bits |= PARPORT_CONTROL_STROBE;118	if (!(value_or & P_OR_AFXN))119		bits |= PARPORT_CONTROL_AUTOFD;120	if (!(value_or & P_OR_INIT))121		bits |= PARPORT_CONTROL_INIT;122	if (value_or & P_OR_SLCT_IN)123		bits |= PARPORT_CONTROL_SELECT;124 125	dprintk((KERN_DEBUG "tcr 0x%x or 0x%x\n", value_tcr, value_or));126	dprintk((KERN_DEBUG "read control 0x%x\n", bits));127	return bits;128}129 130static unsigned char parport_sunbpp_read_control(struct parport *p)131{132	return control_sunbpp_to_pc(p);133}134 135static unsigned char parport_sunbpp_frob_control(struct parport *p,136						 unsigned char mask,137						 unsigned char val)138{139	struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;140	unsigned char value_tcr = sbus_readb(&regs->p_tcr);141	unsigned char value_or = sbus_readb(&regs->p_or);142 143	dprintk((KERN_DEBUG "frob1: tcr 0x%x or 0x%x\n",144		 value_tcr, value_or));145	if (mask & PARPORT_CONTROL_STROBE) {146		if (val & PARPORT_CONTROL_STROBE) {147			value_tcr &= ~P_TCR_DS;148		} else {149			value_tcr |= P_TCR_DS;150		}151	}152	if (mask & PARPORT_CONTROL_AUTOFD) {153		if (val & PARPORT_CONTROL_AUTOFD) {154			value_or &= ~P_OR_AFXN;155		} else {156			value_or |= P_OR_AFXN;157		}158	}159	if (mask & PARPORT_CONTROL_INIT) {160		if (val & PARPORT_CONTROL_INIT) {161			value_or &= ~P_OR_INIT;162		} else {163			value_or |= P_OR_INIT;164		}165	}166	if (mask & PARPORT_CONTROL_SELECT) {167		if (val & PARPORT_CONTROL_SELECT) {168			value_or |= P_OR_SLCT_IN;169		} else {170			value_or &= ~P_OR_SLCT_IN;171		}172	}173 174	sbus_writeb(value_or, &regs->p_or);175	sbus_writeb(value_tcr, &regs->p_tcr);176	dprintk((KERN_DEBUG "frob2: tcr 0x%x or 0x%x\n",177		 value_tcr, value_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 __iomem *regs = (struct bpp_regs __iomem *)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 __iomem *regs = (struct bpp_regs __iomem *)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 struct parport_operations parport_sunbpp_ops = 233{234	.write_data	= parport_sunbpp_write_data,235	.read_data	= parport_sunbpp_read_data,236 237	.write_control	= parport_sunbpp_write_control,238	.read_control	= parport_sunbpp_read_control,239	.frob_control	= parport_sunbpp_frob_control,240 241	.read_status	= parport_sunbpp_read_status,242 243	.enable_irq	= parport_sunbpp_enable_irq,244	.disable_irq	= parport_sunbpp_disable_irq,245 246	.data_forward	= parport_sunbpp_data_forward,247	.data_reverse	= parport_sunbpp_data_reverse,248 249	.init_state	= parport_sunbpp_init_state,250	.save_state	= parport_sunbpp_save_state,251	.restore_state	= parport_sunbpp_restore_state,252 253	.epp_write_data	= parport_ieee1284_epp_write_data,254	.epp_read_data	= parport_ieee1284_epp_read_data,255	.epp_write_addr	= parport_ieee1284_epp_write_addr,256	.epp_read_addr	= parport_ieee1284_epp_read_addr,257 258	.ecp_write_data	= parport_ieee1284_ecp_write_data,259	.ecp_read_data	= parport_ieee1284_ecp_read_data,260	.ecp_write_addr	= parport_ieee1284_ecp_write_addr,261 262	.compat_write_data	= parport_ieee1284_write_compat,263	.nibble_read_data	= parport_ieee1284_read_nibble,264	.byte_read_data		= parport_ieee1284_read_byte,265 266	.owner		= THIS_MODULE,267};268 269static int bpp_probe(struct platform_device *op)270{271	struct parport_operations *ops;272	struct bpp_regs __iomem *regs;273	int irq, dma, err = 0, size;274	unsigned char value_tcr;275	void __iomem *base;276	struct parport *p;277 278	irq = op->archdata.irqs[0];279	base = of_ioremap(&op->resource[0], 0,280			  resource_size(&op->resource[0]),281			  "sunbpp");282	if (!base)283		return -ENODEV;284 285	size = resource_size(&op->resource[0]);286	dma = PARPORT_DMA_NONE;287 288	ops = kmemdup(&parport_sunbpp_ops, sizeof(struct parport_operations),289		      GFP_KERNEL);290	if (!ops) {291		err = -ENOMEM;292		goto out_unmap;293	}294 295	dprintk(("register_port\n"));296	if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) {297		err = -ENOMEM;298		goto out_free_ops;299	}300 301	p->size = size;302	p->dev = &op->dev;303 304	if ((err = request_irq(p->irq, parport_irq_handler,305			       IRQF_SHARED, p->name, p)) != 0) {306		goto out_put_port;307	}308 309	parport_sunbpp_enable_irq(p);310 311	regs = (struct bpp_regs __iomem *)p->base;312 313	value_tcr = sbus_readb(&regs->p_tcr);314	value_tcr &= ~P_TCR_DIR;315	sbus_writeb(value_tcr, &regs->p_tcr);316 317	pr_info("%s: sunbpp at 0x%lx\n", p->name, p->base);318 319	dev_set_drvdata(&op->dev, p);320 321	parport_announce_port(p);322 323	return 0;324 325out_put_port:326	parport_put_port(p);327 328out_free_ops:329	kfree(ops);330 331out_unmap:332	of_iounmap(&op->resource[0], base, size);333 334	return err;335}336 337static void bpp_remove(struct platform_device *op)338{339	struct parport *p = dev_get_drvdata(&op->dev);340	struct parport_operations *ops = p->ops;341 342	parport_remove_port(p);343 344	if (p->irq != PARPORT_IRQ_NONE) {345		parport_sunbpp_disable_irq(p);346		free_irq(p->irq, p);347	}348 349	of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size);350	parport_put_port(p);351	kfree(ops);352 353	dev_set_drvdata(&op->dev, NULL);354}355 356static const struct of_device_id bpp_match[] = {357	{358		.name = "SUNW,bpp",359	},360	{},361};362 363MODULE_DEVICE_TABLE(of, bpp_match);364 365static struct platform_driver bpp_sbus_driver = {366	.driver = {367		.name = "bpp",368		.of_match_table = bpp_match,369	},370	.probe		= bpp_probe,371	.remove_new	= bpp_remove,372};373 374module_platform_driver(bpp_sbus_driver);375 376MODULE_AUTHOR("Derrick J Brashear");377MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");378MODULE_VERSION("2.0");379MODULE_LICENSE("GPL");380