Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* parport_sunbpp.c: Parallel-port routines for SBUS
0003  * 
0004  * Author: Derrick J. Brashear <shadow@dementia.org>
0005  *
0006  * based on work by:
0007  *          Phil Blundell <philb@gnu.org>
0008  *          Tim Waugh <tim@cyberelk.demon.co.uk>
0009  *      Jose Renau <renau@acm.org>
0010  *          David Campbell <campbell@tirian.che.curtin.edu.au>
0011  *          Grant Guenther <grant@torque.net>
0012  *          Eddie C. Dost <ecd@skynet.be>
0013  *          Stephen Williams (steve@icarus.com)
0014  *          Gus Baldauf (gbaldauf@ix.netcom.com)
0015  *          Peter Zaitcev
0016  *          Tom Dyas
0017  *
0018  * Updated to new SBUS device framework: David S. Miller <davem@davemloft.net>
0019  * 
0020  */
0021 
0022 #include <linux/string.h>
0023 #include <linux/module.h>
0024 #include <linux/delay.h>
0025 #include <linux/errno.h>
0026 #include <linux/ioport.h>
0027 #include <linux/kernel.h>
0028 #include <linux/slab.h>
0029 #include <linux/init.h>
0030 #include <linux/of.h>
0031 #include <linux/of_device.h>
0032 
0033 #include <linux/parport.h>
0034 
0035 #include <asm/ptrace.h>
0036 #include <linux/interrupt.h>
0037 
0038 #include <asm/io.h>
0039 #include <asm/oplib.h>           /* OpenProm Library */
0040 #include <asm/dma.h>             /* BPP uses LSI 64854 for DMA */
0041 #include <asm/irq.h>
0042 #include <asm/sunbpp.h>
0043 
0044 #undef __SUNBPP_DEBUG
0045 #ifdef __SUNBPP_DEBUG
0046 #define dprintk(x) printk x
0047 #else
0048 #define dprintk(x)
0049 #endif
0050 
0051 static void parport_sunbpp_disable_irq(struct parport *p)
0052 {
0053     struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
0054     u32 tmp;
0055 
0056     tmp = sbus_readl(&regs->p_csr);
0057     tmp &= ~DMA_INT_ENAB;
0058     sbus_writel(tmp, &regs->p_csr);
0059 }
0060 
0061 static void parport_sunbpp_enable_irq(struct parport *p)
0062 {
0063     struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
0064     u32 tmp;
0065 
0066     tmp = sbus_readl(&regs->p_csr);
0067     tmp |= DMA_INT_ENAB;
0068     sbus_writel(tmp, &regs->p_csr);
0069 }
0070 
0071 static void parport_sunbpp_write_data(struct parport *p, unsigned char d)
0072 {
0073     struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
0074 
0075     sbus_writeb(d, &regs->p_dr);
0076     dprintk((KERN_DEBUG "wrote 0x%x\n", d));
0077 }
0078 
0079 static unsigned char parport_sunbpp_read_data(struct parport *p)
0080 {
0081     struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
0082 
0083     return sbus_readb(&regs->p_dr);
0084 }
0085 
0086 static unsigned char status_sunbpp_to_pc(struct parport *p)
0087 {
0088     struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
0089     unsigned char bits = 0;
0090     unsigned char value_tcr = sbus_readb(&regs->p_tcr);
0091     unsigned char value_ir = sbus_readb(&regs->p_ir);
0092 
0093     if (!(value_ir & P_IR_ERR))
0094         bits |= PARPORT_STATUS_ERROR;
0095     if (!(value_ir & P_IR_SLCT))
0096         bits |= PARPORT_STATUS_SELECT;
0097     if (!(value_ir & P_IR_PE))
0098         bits |= PARPORT_STATUS_PAPEROUT;
0099     if (value_tcr & P_TCR_ACK)
0100         bits |= PARPORT_STATUS_ACK;
0101     if (!(value_tcr & P_TCR_BUSY))
0102         bits |= PARPORT_STATUS_BUSY;
0103 
0104     dprintk((KERN_DEBUG "tcr 0x%x ir 0x%x\n", value_tcr, value_ir));
0105     dprintk((KERN_DEBUG "read status 0x%x\n", bits));
0106     return bits;
0107 }
0108 
0109 static unsigned char control_sunbpp_to_pc(struct parport *p)
0110 {
0111     struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
0112     unsigned char bits = 0;
0113     unsigned char value_tcr = sbus_readb(&regs->p_tcr);
0114     unsigned char value_or = sbus_readb(&regs->p_or);
0115 
0116     if (!(value_tcr & P_TCR_DS))
0117         bits |= PARPORT_CONTROL_STROBE;
0118     if (!(value_or & P_OR_AFXN))
0119         bits |= PARPORT_CONTROL_AUTOFD;
0120     if (!(value_or & P_OR_INIT))
0121         bits |= PARPORT_CONTROL_INIT;
0122     if (value_or & P_OR_SLCT_IN)
0123         bits |= PARPORT_CONTROL_SELECT;
0124 
0125     dprintk((KERN_DEBUG "tcr 0x%x or 0x%x\n", value_tcr, value_or));
0126     dprintk((KERN_DEBUG "read control 0x%x\n", bits));
0127     return bits;
0128 }
0129 
0130 static unsigned char parport_sunbpp_read_control(struct parport *p)
0131 {
0132     return control_sunbpp_to_pc(p);
0133 }
0134 
0135 static unsigned char parport_sunbpp_frob_control(struct parport *p,
0136                          unsigned char mask,
0137                          unsigned char val)
0138 {
0139     struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
0140     unsigned char value_tcr = sbus_readb(&regs->p_tcr);
0141     unsigned char value_or = sbus_readb(&regs->p_or);
0142 
0143     dprintk((KERN_DEBUG "frob1: tcr 0x%x or 0x%x\n",
0144          value_tcr, value_or));
0145     if (mask & PARPORT_CONTROL_STROBE) {
0146         if (val & PARPORT_CONTROL_STROBE) {
0147             value_tcr &= ~P_TCR_DS;
0148         } else {
0149             value_tcr |= P_TCR_DS;
0150         }
0151     }
0152     if (mask & PARPORT_CONTROL_AUTOFD) {
0153         if (val & PARPORT_CONTROL_AUTOFD) {
0154             value_or &= ~P_OR_AFXN;
0155         } else {
0156             value_or |= P_OR_AFXN;
0157         }
0158     }
0159     if (mask & PARPORT_CONTROL_INIT) {
0160         if (val & PARPORT_CONTROL_INIT) {
0161             value_or &= ~P_OR_INIT;
0162         } else {
0163             value_or |= P_OR_INIT;
0164         }
0165     }
0166     if (mask & PARPORT_CONTROL_SELECT) {
0167         if (val & PARPORT_CONTROL_SELECT) {
0168             value_or |= P_OR_SLCT_IN;
0169         } else {
0170             value_or &= ~P_OR_SLCT_IN;
0171         }
0172     }
0173 
0174     sbus_writeb(value_or, &regs->p_or);
0175     sbus_writeb(value_tcr, &regs->p_tcr);
0176     dprintk((KERN_DEBUG "frob2: tcr 0x%x or 0x%x\n",
0177          value_tcr, value_or));
0178     return parport_sunbpp_read_control(p);
0179 }
0180 
0181 static void parport_sunbpp_write_control(struct parport *p, unsigned char d)
0182 {
0183     const unsigned char wm = (PARPORT_CONTROL_STROBE |
0184                   PARPORT_CONTROL_AUTOFD |
0185                   PARPORT_CONTROL_INIT |
0186                   PARPORT_CONTROL_SELECT);
0187 
0188     parport_sunbpp_frob_control (p, wm, d & wm);
0189 }
0190 
0191 static unsigned char parport_sunbpp_read_status(struct parport *p)
0192 {
0193     return status_sunbpp_to_pc(p);
0194 }
0195 
0196 static void parport_sunbpp_data_forward (struct parport *p)
0197 {
0198     struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
0199     unsigned char value_tcr = sbus_readb(&regs->p_tcr);
0200 
0201     dprintk((KERN_DEBUG "forward\n"));
0202     value_tcr &= ~P_TCR_DIR;
0203     sbus_writeb(value_tcr, &regs->p_tcr);
0204 }
0205 
0206 static void parport_sunbpp_data_reverse (struct parport *p)
0207 {
0208     struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
0209     u8 val = sbus_readb(&regs->p_tcr);
0210 
0211     dprintk((KERN_DEBUG "reverse\n"));
0212     val |= P_TCR_DIR;
0213     sbus_writeb(val, &regs->p_tcr);
0214 }
0215 
0216 static void parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s)
0217 {
0218     s->u.pc.ctr = 0xc;
0219     s->u.pc.ecr = 0x0;
0220 }
0221 
0222 static void parport_sunbpp_save_state(struct parport *p, struct parport_state *s)
0223 {
0224     s->u.pc.ctr = parport_sunbpp_read_control(p);
0225 }
0226 
0227 static void parport_sunbpp_restore_state(struct parport *p, struct parport_state *s)
0228 {
0229     parport_sunbpp_write_control(p, s->u.pc.ctr);
0230 }
0231 
0232 static struct parport_operations parport_sunbpp_ops = 
0233 {
0234     .write_data = parport_sunbpp_write_data,
0235     .read_data  = parport_sunbpp_read_data,
0236 
0237     .write_control  = parport_sunbpp_write_control,
0238     .read_control   = parport_sunbpp_read_control,
0239     .frob_control   = parport_sunbpp_frob_control,
0240 
0241     .read_status    = parport_sunbpp_read_status,
0242 
0243     .enable_irq = parport_sunbpp_enable_irq,
0244     .disable_irq    = parport_sunbpp_disable_irq,
0245 
0246     .data_forward   = parport_sunbpp_data_forward,
0247     .data_reverse   = parport_sunbpp_data_reverse,
0248 
0249     .init_state = parport_sunbpp_init_state,
0250     .save_state = parport_sunbpp_save_state,
0251     .restore_state  = parport_sunbpp_restore_state,
0252 
0253     .epp_write_data = parport_ieee1284_epp_write_data,
0254     .epp_read_data  = parport_ieee1284_epp_read_data,
0255     .epp_write_addr = parport_ieee1284_epp_write_addr,
0256     .epp_read_addr  = parport_ieee1284_epp_read_addr,
0257 
0258     .ecp_write_data = parport_ieee1284_ecp_write_data,
0259     .ecp_read_data  = parport_ieee1284_ecp_read_data,
0260     .ecp_write_addr = parport_ieee1284_ecp_write_addr,
0261 
0262     .compat_write_data  = parport_ieee1284_write_compat,
0263     .nibble_read_data   = parport_ieee1284_read_nibble,
0264     .byte_read_data     = parport_ieee1284_read_byte,
0265 
0266     .owner      = THIS_MODULE,
0267 };
0268 
0269 static int bpp_probe(struct platform_device *op)
0270 {
0271     struct parport_operations *ops;
0272     struct bpp_regs __iomem *regs;
0273     int irq, dma, err = 0, size;
0274     unsigned char value_tcr;
0275     void __iomem *base;
0276     struct parport *p;
0277 
0278     irq = op->archdata.irqs[0];
0279     base = of_ioremap(&op->resource[0], 0,
0280               resource_size(&op->resource[0]),
0281               "sunbpp");
0282     if (!base)
0283         return -ENODEV;
0284 
0285     size = resource_size(&op->resource[0]);
0286     dma = PARPORT_DMA_NONE;
0287 
0288     ops = kmemdup(&parport_sunbpp_ops, sizeof(struct parport_operations),
0289               GFP_KERNEL);
0290     if (!ops) {
0291         err = -ENOMEM;
0292         goto out_unmap;
0293     }
0294 
0295     dprintk(("register_port\n"));
0296     if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) {
0297         err = -ENOMEM;
0298         goto out_free_ops;
0299     }
0300 
0301     p->size = size;
0302     p->dev = &op->dev;
0303 
0304     if ((err = request_irq(p->irq, parport_irq_handler,
0305                    IRQF_SHARED, p->name, p)) != 0) {
0306         goto out_put_port;
0307     }
0308 
0309     parport_sunbpp_enable_irq(p);
0310 
0311     regs = (struct bpp_regs __iomem *)p->base;
0312 
0313     value_tcr = sbus_readb(&regs->p_tcr);
0314     value_tcr &= ~P_TCR_DIR;
0315     sbus_writeb(value_tcr, &regs->p_tcr);
0316 
0317     pr_info("%s: sunbpp at 0x%lx\n", p->name, p->base);
0318 
0319     dev_set_drvdata(&op->dev, p);
0320 
0321     parport_announce_port(p);
0322 
0323     return 0;
0324 
0325 out_put_port:
0326     parport_put_port(p);
0327 
0328 out_free_ops:
0329     kfree(ops);
0330 
0331 out_unmap:
0332     of_iounmap(&op->resource[0], base, size);
0333 
0334     return err;
0335 }
0336 
0337 static int bpp_remove(struct platform_device *op)
0338 {
0339     struct parport *p = dev_get_drvdata(&op->dev);
0340     struct parport_operations *ops = p->ops;
0341 
0342     parport_remove_port(p);
0343 
0344     if (p->irq != PARPORT_IRQ_NONE) {
0345         parport_sunbpp_disable_irq(p);
0346         free_irq(p->irq, p);
0347     }
0348 
0349     of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size);
0350     parport_put_port(p);
0351     kfree(ops);
0352 
0353     dev_set_drvdata(&op->dev, NULL);
0354 
0355     return 0;
0356 }
0357 
0358 static const struct of_device_id bpp_match[] = {
0359     {
0360         .name = "SUNW,bpp",
0361     },
0362     {},
0363 };
0364 
0365 MODULE_DEVICE_TABLE(of, bpp_match);
0366 
0367 static struct platform_driver bpp_sbus_driver = {
0368     .driver = {
0369         .name = "bpp",
0370         .of_match_table = bpp_match,
0371     },
0372     .probe      = bpp_probe,
0373     .remove     = bpp_remove,
0374 };
0375 
0376 module_platform_driver(bpp_sbus_driver);
0377 
0378 MODULE_AUTHOR("Derrick J Brashear");
0379 MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
0380 MODULE_VERSION("2.0");
0381 MODULE_LICENSE("GPL");