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(®s->p_csr);57 tmp &= ~DMA_INT_ENAB;58 sbus_writel(tmp, ®s->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(®s->p_csr);67 tmp |= DMA_INT_ENAB;68 sbus_writel(tmp, ®s->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, ®s->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(®s->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(®s->p_tcr);91 unsigned char value_ir = sbus_readb(®s->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(®s->p_tcr);114 unsigned char value_or = sbus_readb(®s->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(®s->p_tcr);141 unsigned char value_or = sbus_readb(®s->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, ®s->p_or);175 sbus_writeb(value_tcr, ®s->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(®s->p_tcr);200 201 dprintk((KERN_DEBUG "forward\n"));202 value_tcr &= ~P_TCR_DIR;203 sbus_writeb(value_tcr, ®s->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(®s->p_tcr);210 211 dprintk((KERN_DEBUG "reverse\n"));212 val |= P_TCR_DIR;213 sbus_writeb(val, ®s->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(®s->p_tcr);314 value_tcr &= ~P_TCR_DIR;315 sbus_writeb(value_tcr, ®s->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