18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* parport_sunbpp.c: Parallel-port routines for SBUS 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author: Derrick J. Brashear <shadow@dementia.org> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * based on work by: 78c2ecf20Sopenharmony_ci * Phil Blundell <philb@gnu.org> 88c2ecf20Sopenharmony_ci * Tim Waugh <tim@cyberelk.demon.co.uk> 98c2ecf20Sopenharmony_ci * Jose Renau <renau@acm.org> 108c2ecf20Sopenharmony_ci * David Campbell <campbell@tirian.che.curtin.edu.au> 118c2ecf20Sopenharmony_ci * Grant Guenther <grant@torque.net> 128c2ecf20Sopenharmony_ci * Eddie C. Dost <ecd@skynet.be> 138c2ecf20Sopenharmony_ci * Stephen Williams (steve@icarus.com) 148c2ecf20Sopenharmony_ci * Gus Baldauf (gbaldauf@ix.netcom.com) 158c2ecf20Sopenharmony_ci * Peter Zaitcev 168c2ecf20Sopenharmony_ci * Tom Dyas 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Updated to new SBUS device framework: David S. Miller <davem@davemloft.net> 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/string.h> 238c2ecf20Sopenharmony_ci#include <linux/module.h> 248c2ecf20Sopenharmony_ci#include <linux/delay.h> 258c2ecf20Sopenharmony_ci#include <linux/errno.h> 268c2ecf20Sopenharmony_ci#include <linux/ioport.h> 278c2ecf20Sopenharmony_ci#include <linux/kernel.h> 288c2ecf20Sopenharmony_ci#include <linux/slab.h> 298c2ecf20Sopenharmony_ci#include <linux/init.h> 308c2ecf20Sopenharmony_ci#include <linux/of.h> 318c2ecf20Sopenharmony_ci#include <linux/of_device.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/parport.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 368c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <asm/io.h> 398c2ecf20Sopenharmony_ci#include <asm/oplib.h> /* OpenProm Library */ 408c2ecf20Sopenharmony_ci#include <asm/dma.h> /* BPP uses LSI 64854 for DMA */ 418c2ecf20Sopenharmony_ci#include <asm/irq.h> 428c2ecf20Sopenharmony_ci#include <asm/sunbpp.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#undef __SUNBPP_DEBUG 458c2ecf20Sopenharmony_ci#ifdef __SUNBPP_DEBUG 468c2ecf20Sopenharmony_ci#define dprintk(x) printk x 478c2ecf20Sopenharmony_ci#else 488c2ecf20Sopenharmony_ci#define dprintk(x) 498c2ecf20Sopenharmony_ci#endif 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void parport_sunbpp_disable_irq(struct parport *p) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; 548c2ecf20Sopenharmony_ci u32 tmp; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci tmp = sbus_readl(®s->p_csr); 578c2ecf20Sopenharmony_ci tmp &= ~DMA_INT_ENAB; 588c2ecf20Sopenharmony_ci sbus_writel(tmp, ®s->p_csr); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic void parport_sunbpp_enable_irq(struct parport *p) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; 648c2ecf20Sopenharmony_ci u32 tmp; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci tmp = sbus_readl(®s->p_csr); 678c2ecf20Sopenharmony_ci tmp |= DMA_INT_ENAB; 688c2ecf20Sopenharmony_ci sbus_writel(tmp, ®s->p_csr); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void parport_sunbpp_write_data(struct parport *p, unsigned char d) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci sbus_writeb(d, ®s->p_dr); 768c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "wrote 0x%x\n", d)); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic unsigned char parport_sunbpp_read_data(struct parport *p) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return sbus_readb(®s->p_dr); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic unsigned char status_sunbpp_to_pc(struct parport *p) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; 898c2ecf20Sopenharmony_ci unsigned char bits = 0; 908c2ecf20Sopenharmony_ci unsigned char value_tcr = sbus_readb(®s->p_tcr); 918c2ecf20Sopenharmony_ci unsigned char value_ir = sbus_readb(®s->p_ir); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (!(value_ir & P_IR_ERR)) 948c2ecf20Sopenharmony_ci bits |= PARPORT_STATUS_ERROR; 958c2ecf20Sopenharmony_ci if (!(value_ir & P_IR_SLCT)) 968c2ecf20Sopenharmony_ci bits |= PARPORT_STATUS_SELECT; 978c2ecf20Sopenharmony_ci if (!(value_ir & P_IR_PE)) 988c2ecf20Sopenharmony_ci bits |= PARPORT_STATUS_PAPEROUT; 998c2ecf20Sopenharmony_ci if (value_tcr & P_TCR_ACK) 1008c2ecf20Sopenharmony_ci bits |= PARPORT_STATUS_ACK; 1018c2ecf20Sopenharmony_ci if (!(value_tcr & P_TCR_BUSY)) 1028c2ecf20Sopenharmony_ci bits |= PARPORT_STATUS_BUSY; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "tcr 0x%x ir 0x%x\n", value_tcr, value_ir)); 1058c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "read status 0x%x\n", bits)); 1068c2ecf20Sopenharmony_ci return bits; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic unsigned char control_sunbpp_to_pc(struct parport *p) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; 1128c2ecf20Sopenharmony_ci unsigned char bits = 0; 1138c2ecf20Sopenharmony_ci unsigned char value_tcr = sbus_readb(®s->p_tcr); 1148c2ecf20Sopenharmony_ci unsigned char value_or = sbus_readb(®s->p_or); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (!(value_tcr & P_TCR_DS)) 1178c2ecf20Sopenharmony_ci bits |= PARPORT_CONTROL_STROBE; 1188c2ecf20Sopenharmony_ci if (!(value_or & P_OR_AFXN)) 1198c2ecf20Sopenharmony_ci bits |= PARPORT_CONTROL_AUTOFD; 1208c2ecf20Sopenharmony_ci if (!(value_or & P_OR_INIT)) 1218c2ecf20Sopenharmony_ci bits |= PARPORT_CONTROL_INIT; 1228c2ecf20Sopenharmony_ci if (value_or & P_OR_SLCT_IN) 1238c2ecf20Sopenharmony_ci bits |= PARPORT_CONTROL_SELECT; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "tcr 0x%x or 0x%x\n", value_tcr, value_or)); 1268c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "read control 0x%x\n", bits)); 1278c2ecf20Sopenharmony_ci return bits; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic unsigned char parport_sunbpp_read_control(struct parport *p) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci return control_sunbpp_to_pc(p); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic unsigned char parport_sunbpp_frob_control(struct parport *p, 1368c2ecf20Sopenharmony_ci unsigned char mask, 1378c2ecf20Sopenharmony_ci unsigned char val) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; 1408c2ecf20Sopenharmony_ci unsigned char value_tcr = sbus_readb(®s->p_tcr); 1418c2ecf20Sopenharmony_ci unsigned char value_or = sbus_readb(®s->p_or); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "frob1: tcr 0x%x or 0x%x\n", 1448c2ecf20Sopenharmony_ci value_tcr, value_or)); 1458c2ecf20Sopenharmony_ci if (mask & PARPORT_CONTROL_STROBE) { 1468c2ecf20Sopenharmony_ci if (val & PARPORT_CONTROL_STROBE) { 1478c2ecf20Sopenharmony_ci value_tcr &= ~P_TCR_DS; 1488c2ecf20Sopenharmony_ci } else { 1498c2ecf20Sopenharmony_ci value_tcr |= P_TCR_DS; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci if (mask & PARPORT_CONTROL_AUTOFD) { 1538c2ecf20Sopenharmony_ci if (val & PARPORT_CONTROL_AUTOFD) { 1548c2ecf20Sopenharmony_ci value_or &= ~P_OR_AFXN; 1558c2ecf20Sopenharmony_ci } else { 1568c2ecf20Sopenharmony_ci value_or |= P_OR_AFXN; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci if (mask & PARPORT_CONTROL_INIT) { 1608c2ecf20Sopenharmony_ci if (val & PARPORT_CONTROL_INIT) { 1618c2ecf20Sopenharmony_ci value_or &= ~P_OR_INIT; 1628c2ecf20Sopenharmony_ci } else { 1638c2ecf20Sopenharmony_ci value_or |= P_OR_INIT; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci if (mask & PARPORT_CONTROL_SELECT) { 1678c2ecf20Sopenharmony_ci if (val & PARPORT_CONTROL_SELECT) { 1688c2ecf20Sopenharmony_ci value_or |= P_OR_SLCT_IN; 1698c2ecf20Sopenharmony_ci } else { 1708c2ecf20Sopenharmony_ci value_or &= ~P_OR_SLCT_IN; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci sbus_writeb(value_or, ®s->p_or); 1758c2ecf20Sopenharmony_ci sbus_writeb(value_tcr, ®s->p_tcr); 1768c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "frob2: tcr 0x%x or 0x%x\n", 1778c2ecf20Sopenharmony_ci value_tcr, value_or)); 1788c2ecf20Sopenharmony_ci return parport_sunbpp_read_control(p); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void parport_sunbpp_write_control(struct parport *p, unsigned char d) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci const unsigned char wm = (PARPORT_CONTROL_STROBE | 1848c2ecf20Sopenharmony_ci PARPORT_CONTROL_AUTOFD | 1858c2ecf20Sopenharmony_ci PARPORT_CONTROL_INIT | 1868c2ecf20Sopenharmony_ci PARPORT_CONTROL_SELECT); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci parport_sunbpp_frob_control (p, wm, d & wm); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic unsigned char parport_sunbpp_read_status(struct parport *p) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci return status_sunbpp_to_pc(p); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void parport_sunbpp_data_forward (struct parport *p) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; 1998c2ecf20Sopenharmony_ci unsigned char value_tcr = sbus_readb(®s->p_tcr); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "forward\n")); 2028c2ecf20Sopenharmony_ci value_tcr &= ~P_TCR_DIR; 2038c2ecf20Sopenharmony_ci sbus_writeb(value_tcr, ®s->p_tcr); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic void parport_sunbpp_data_reverse (struct parport *p) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; 2098c2ecf20Sopenharmony_ci u8 val = sbus_readb(®s->p_tcr); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "reverse\n")); 2128c2ecf20Sopenharmony_ci val |= P_TCR_DIR; 2138c2ecf20Sopenharmony_ci sbus_writeb(val, ®s->p_tcr); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic void parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci s->u.pc.ctr = 0xc; 2198c2ecf20Sopenharmony_ci s->u.pc.ecr = 0x0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void parport_sunbpp_save_state(struct parport *p, struct parport_state *s) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci s->u.pc.ctr = parport_sunbpp_read_control(p); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void parport_sunbpp_restore_state(struct parport *p, struct parport_state *s) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci parport_sunbpp_write_control(p, s->u.pc.ctr); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic struct parport_operations parport_sunbpp_ops = 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci .write_data = parport_sunbpp_write_data, 2358c2ecf20Sopenharmony_ci .read_data = parport_sunbpp_read_data, 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci .write_control = parport_sunbpp_write_control, 2388c2ecf20Sopenharmony_ci .read_control = parport_sunbpp_read_control, 2398c2ecf20Sopenharmony_ci .frob_control = parport_sunbpp_frob_control, 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci .read_status = parport_sunbpp_read_status, 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci .enable_irq = parport_sunbpp_enable_irq, 2448c2ecf20Sopenharmony_ci .disable_irq = parport_sunbpp_disable_irq, 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci .data_forward = parport_sunbpp_data_forward, 2478c2ecf20Sopenharmony_ci .data_reverse = parport_sunbpp_data_reverse, 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci .init_state = parport_sunbpp_init_state, 2508c2ecf20Sopenharmony_ci .save_state = parport_sunbpp_save_state, 2518c2ecf20Sopenharmony_ci .restore_state = parport_sunbpp_restore_state, 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci .epp_write_data = parport_ieee1284_epp_write_data, 2548c2ecf20Sopenharmony_ci .epp_read_data = parport_ieee1284_epp_read_data, 2558c2ecf20Sopenharmony_ci .epp_write_addr = parport_ieee1284_epp_write_addr, 2568c2ecf20Sopenharmony_ci .epp_read_addr = parport_ieee1284_epp_read_addr, 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci .ecp_write_data = parport_ieee1284_ecp_write_data, 2598c2ecf20Sopenharmony_ci .ecp_read_data = parport_ieee1284_ecp_read_data, 2608c2ecf20Sopenharmony_ci .ecp_write_addr = parport_ieee1284_ecp_write_addr, 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci .compat_write_data = parport_ieee1284_write_compat, 2638c2ecf20Sopenharmony_ci .nibble_read_data = parport_ieee1284_read_nibble, 2648c2ecf20Sopenharmony_ci .byte_read_data = parport_ieee1284_read_byte, 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int bpp_probe(struct platform_device *op) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct parport_operations *ops; 2728c2ecf20Sopenharmony_ci struct bpp_regs __iomem *regs; 2738c2ecf20Sopenharmony_ci int irq, dma, err = 0, size; 2748c2ecf20Sopenharmony_ci unsigned char value_tcr; 2758c2ecf20Sopenharmony_ci void __iomem *base; 2768c2ecf20Sopenharmony_ci struct parport *p; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci irq = op->archdata.irqs[0]; 2798c2ecf20Sopenharmony_ci base = of_ioremap(&op->resource[0], 0, 2808c2ecf20Sopenharmony_ci resource_size(&op->resource[0]), 2818c2ecf20Sopenharmony_ci "sunbpp"); 2828c2ecf20Sopenharmony_ci if (!base) 2838c2ecf20Sopenharmony_ci return -ENODEV; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci size = resource_size(&op->resource[0]); 2868c2ecf20Sopenharmony_ci dma = PARPORT_DMA_NONE; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci ops = kmemdup(&parport_sunbpp_ops, sizeof(struct parport_operations), 2898c2ecf20Sopenharmony_ci GFP_KERNEL); 2908c2ecf20Sopenharmony_ci if (!ops) { 2918c2ecf20Sopenharmony_ci err = -ENOMEM; 2928c2ecf20Sopenharmony_ci goto out_unmap; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci dprintk(("register_port\n")); 2968c2ecf20Sopenharmony_ci if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) { 2978c2ecf20Sopenharmony_ci err = -ENOMEM; 2988c2ecf20Sopenharmony_ci goto out_free_ops; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci p->size = size; 3028c2ecf20Sopenharmony_ci p->dev = &op->dev; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if ((err = request_irq(p->irq, parport_irq_handler, 3058c2ecf20Sopenharmony_ci IRQF_SHARED, p->name, p)) != 0) { 3068c2ecf20Sopenharmony_ci goto out_put_port; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci parport_sunbpp_enable_irq(p); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci regs = (struct bpp_regs __iomem *)p->base; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci value_tcr = sbus_readb(®s->p_tcr); 3148c2ecf20Sopenharmony_ci value_tcr &= ~P_TCR_DIR; 3158c2ecf20Sopenharmony_ci sbus_writeb(value_tcr, ®s->p_tcr); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci pr_info("%s: sunbpp at 0x%lx\n", p->name, p->base); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci dev_set_drvdata(&op->dev, p); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci parport_announce_port(p); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ciout_put_port: 3268c2ecf20Sopenharmony_ci parport_put_port(p); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ciout_free_ops: 3298c2ecf20Sopenharmony_ci kfree(ops); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ciout_unmap: 3328c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], base, size); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return err; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int bpp_remove(struct platform_device *op) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct parport *p = dev_get_drvdata(&op->dev); 3408c2ecf20Sopenharmony_ci struct parport_operations *ops = p->ops; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci parport_remove_port(p); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) { 3458c2ecf20Sopenharmony_ci parport_sunbpp_disable_irq(p); 3468c2ecf20Sopenharmony_ci free_irq(p->irq, p); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size); 3508c2ecf20Sopenharmony_ci parport_put_port(p); 3518c2ecf20Sopenharmony_ci kfree(ops); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci dev_set_drvdata(&op->dev, NULL); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic const struct of_device_id bpp_match[] = { 3598c2ecf20Sopenharmony_ci { 3608c2ecf20Sopenharmony_ci .name = "SUNW,bpp", 3618c2ecf20Sopenharmony_ci }, 3628c2ecf20Sopenharmony_ci {}, 3638c2ecf20Sopenharmony_ci}; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bpp_match); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic struct platform_driver bpp_sbus_driver = { 3688c2ecf20Sopenharmony_ci .driver = { 3698c2ecf20Sopenharmony_ci .name = "bpp", 3708c2ecf20Sopenharmony_ci .of_match_table = bpp_match, 3718c2ecf20Sopenharmony_ci }, 3728c2ecf20Sopenharmony_ci .probe = bpp_probe, 3738c2ecf20Sopenharmony_ci .remove = bpp_remove, 3748c2ecf20Sopenharmony_ci}; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cimodule_platform_driver(bpp_sbus_driver); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ciMODULE_AUTHOR("Derrick J Brashear"); 3798c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port"); 3808c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port"); 3818c2ecf20Sopenharmony_ciMODULE_VERSION("2.0"); 3828c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 383