Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* linux/drivers/parport/parport_ax88796.c
0003  *
0004  * (c) 2005,2006 Simtec Electronics
0005  *  Ben Dooks <ben@simtec.co.uk>
0006 */
0007 
0008 #include <linux/module.h>
0009 #include <linux/kernel.h>
0010 #include <linux/parport.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/errno.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/slab.h>
0015 
0016 #include <asm/io.h>
0017 #include <asm/irq.h>
0018 
0019 #define AX_SPR_BUSY     (1<<7)
0020 #define AX_SPR_ACK      (1<<6)
0021 #define AX_SPR_PE       (1<<5)
0022 #define AX_SPR_SLCT     (1<<4)
0023 #define AX_SPR_ERR      (1<<3)
0024 
0025 #define AX_CPR_nDOE     (1<<5)
0026 #define AX_CPR_SLCTIN       (1<<3)
0027 #define AX_CPR_nINIT        (1<<2)
0028 #define AX_CPR_ATFD     (1<<1)
0029 #define AX_CPR_STRB     (1<<0)
0030 
0031 struct ax_drvdata {
0032     struct parport      *parport;
0033     struct parport_state     suspend;
0034 
0035     struct device       *dev;
0036     struct resource     *io;
0037 
0038     unsigned char        irq_enabled;
0039 
0040     void __iomem        *base;
0041     void __iomem        *spp_data;
0042     void __iomem        *spp_spr;
0043     void __iomem        *spp_cpr;
0044 };
0045 
0046 static inline struct ax_drvdata *pp_to_drv(struct parport *p)
0047 {
0048     return p->private_data;
0049 }
0050 
0051 static unsigned char
0052 parport_ax88796_read_data(struct parport *p)
0053 {
0054     struct ax_drvdata *dd = pp_to_drv(p);
0055 
0056     return readb(dd->spp_data);
0057 }
0058 
0059 static void
0060 parport_ax88796_write_data(struct parport *p, unsigned char data)
0061 {
0062     struct ax_drvdata *dd = pp_to_drv(p);
0063 
0064     writeb(data, dd->spp_data);
0065 }
0066 
0067 static unsigned char
0068 parport_ax88796_read_control(struct parport *p)
0069 {
0070     struct ax_drvdata *dd = pp_to_drv(p);
0071     unsigned int cpr = readb(dd->spp_cpr);
0072     unsigned int ret = 0;
0073 
0074     if (!(cpr & AX_CPR_STRB))
0075         ret |= PARPORT_CONTROL_STROBE;
0076 
0077     if (!(cpr & AX_CPR_ATFD))
0078         ret |= PARPORT_CONTROL_AUTOFD;
0079 
0080     if (cpr & AX_CPR_nINIT)
0081         ret |= PARPORT_CONTROL_INIT;
0082 
0083     if (!(cpr & AX_CPR_SLCTIN))
0084         ret |= PARPORT_CONTROL_SELECT;
0085 
0086     return ret;
0087 }
0088 
0089 static void
0090 parport_ax88796_write_control(struct parport *p, unsigned char control)
0091 {
0092     struct ax_drvdata *dd = pp_to_drv(p);
0093     unsigned int cpr = readb(dd->spp_cpr);
0094 
0095     cpr &= AX_CPR_nDOE;
0096 
0097     if (!(control & PARPORT_CONTROL_STROBE))
0098         cpr |= AX_CPR_STRB;
0099 
0100     if (!(control & PARPORT_CONTROL_AUTOFD))
0101         cpr |= AX_CPR_ATFD;
0102 
0103     if (control & PARPORT_CONTROL_INIT)
0104         cpr |= AX_CPR_nINIT;
0105 
0106     if (!(control & PARPORT_CONTROL_SELECT))
0107         cpr |= AX_CPR_SLCTIN;
0108 
0109     dev_dbg(dd->dev, "write_control: ctrl=%02x, cpr=%02x\n", control, cpr);
0110     writeb(cpr, dd->spp_cpr);
0111 
0112     if (parport_ax88796_read_control(p) != control) {
0113         dev_err(dd->dev, "write_control: read != set (%02x, %02x)\n",
0114             parport_ax88796_read_control(p), control);
0115     }
0116 }
0117 
0118 static unsigned char
0119 parport_ax88796_read_status(struct parport *p)
0120 {
0121     struct ax_drvdata *dd = pp_to_drv(p);
0122     unsigned int status = readb(dd->spp_spr);
0123     unsigned int ret = 0;
0124 
0125     if (status & AX_SPR_BUSY)
0126         ret |= PARPORT_STATUS_BUSY;
0127 
0128     if (status & AX_SPR_ACK)
0129         ret |= PARPORT_STATUS_ACK;
0130 
0131     if (status & AX_SPR_ERR)
0132         ret |= PARPORT_STATUS_ERROR;
0133 
0134     if (status & AX_SPR_SLCT)
0135         ret |= PARPORT_STATUS_SELECT;
0136 
0137     if (status & AX_SPR_PE)
0138         ret |= PARPORT_STATUS_PAPEROUT;
0139 
0140     return ret;
0141 }
0142 
0143 static unsigned char
0144 parport_ax88796_frob_control(struct parport *p, unsigned char mask,
0145                  unsigned char val)
0146 {
0147     struct ax_drvdata *dd = pp_to_drv(p);
0148     unsigned char old = parport_ax88796_read_control(p);
0149 
0150     dev_dbg(dd->dev, "frob: mask=%02x, val=%02x, old=%02x\n",
0151         mask, val, old);
0152 
0153     parport_ax88796_write_control(p, (old & ~mask) | val);
0154     return old;
0155 }
0156 
0157 static void
0158 parport_ax88796_enable_irq(struct parport *p)
0159 {
0160     struct ax_drvdata *dd = pp_to_drv(p);
0161     unsigned long flags;
0162 
0163     local_irq_save(flags);
0164     if (!dd->irq_enabled) {
0165         enable_irq(p->irq);
0166         dd->irq_enabled = 1;
0167     }
0168     local_irq_restore(flags);
0169 }
0170 
0171 static void
0172 parport_ax88796_disable_irq(struct parport *p)
0173 {
0174     struct ax_drvdata *dd = pp_to_drv(p);
0175     unsigned long flags;
0176 
0177     local_irq_save(flags);
0178     if (dd->irq_enabled) {
0179         disable_irq(p->irq);
0180         dd->irq_enabled = 0;
0181     }
0182     local_irq_restore(flags);
0183 }
0184 
0185 static void
0186 parport_ax88796_data_forward(struct parport *p)
0187 {
0188     struct ax_drvdata *dd = pp_to_drv(p);
0189     void __iomem *cpr = dd->spp_cpr;
0190 
0191     writeb((readb(cpr) & ~AX_CPR_nDOE), cpr);
0192 }
0193 
0194 static void
0195 parport_ax88796_data_reverse(struct parport *p)
0196 {
0197     struct ax_drvdata *dd = pp_to_drv(p);
0198     void __iomem *cpr = dd->spp_cpr;
0199 
0200     writeb(readb(cpr) | AX_CPR_nDOE, cpr);
0201 }
0202 
0203 static void
0204 parport_ax88796_init_state(struct pardevice *d, struct parport_state *s)
0205 {
0206     struct ax_drvdata *dd = pp_to_drv(d->port);
0207 
0208     memset(s, 0, sizeof(struct parport_state));
0209 
0210     dev_dbg(dd->dev, "init_state: %p: state=%p\n", d, s);
0211     s->u.ax88796.cpr = readb(dd->spp_cpr);
0212 }
0213 
0214 static void
0215 parport_ax88796_save_state(struct parport *p, struct parport_state *s)
0216 {
0217     struct ax_drvdata *dd = pp_to_drv(p);
0218 
0219     dev_dbg(dd->dev, "save_state: %p: state=%p\n", p, s);
0220     s->u.ax88796.cpr = readb(dd->spp_cpr);
0221 }
0222 
0223 static void
0224 parport_ax88796_restore_state(struct parport *p, struct parport_state *s)
0225 {
0226     struct ax_drvdata *dd = pp_to_drv(p);
0227 
0228     dev_dbg(dd->dev, "restore_state: %p: state=%p\n", p, s);
0229     writeb(s->u.ax88796.cpr, dd->spp_cpr);
0230 }
0231 
0232 static struct parport_operations parport_ax88796_ops = {
0233     .write_data = parport_ax88796_write_data,
0234     .read_data  = parport_ax88796_read_data,
0235 
0236     .write_control  = parport_ax88796_write_control,
0237     .read_control   = parport_ax88796_read_control,
0238     .frob_control   = parport_ax88796_frob_control,
0239 
0240     .read_status    = parport_ax88796_read_status,
0241 
0242     .enable_irq = parport_ax88796_enable_irq,
0243     .disable_irq    = parport_ax88796_disable_irq,
0244 
0245     .data_forward   = parport_ax88796_data_forward,
0246     .data_reverse   = parport_ax88796_data_reverse,
0247 
0248     .init_state = parport_ax88796_init_state,
0249     .save_state = parport_ax88796_save_state,
0250     .restore_state  = parport_ax88796_restore_state,
0251 
0252     .epp_write_data = parport_ieee1284_epp_write_data,
0253     .epp_read_data  = parport_ieee1284_epp_read_data,
0254     .epp_write_addr = parport_ieee1284_epp_write_addr,
0255     .epp_read_addr  = parport_ieee1284_epp_read_addr,
0256 
0257     .ecp_write_data = parport_ieee1284_ecp_write_data,
0258     .ecp_read_data  = parport_ieee1284_ecp_read_data,
0259     .ecp_write_addr = parport_ieee1284_ecp_write_addr,
0260 
0261     .compat_write_data  = parport_ieee1284_write_compat,
0262     .nibble_read_data   = parport_ieee1284_read_nibble,
0263     .byte_read_data     = parport_ieee1284_read_byte,
0264 
0265     .owner      = THIS_MODULE,
0266 };
0267 
0268 static int parport_ax88796_probe(struct platform_device *pdev)
0269 {
0270     struct device *_dev = &pdev->dev;
0271     struct ax_drvdata *dd;
0272     struct parport *pp;
0273     struct resource *res;
0274     unsigned long size;
0275     int spacing;
0276     int irq;
0277     int ret;
0278 
0279     dd = kzalloc(sizeof(*dd), GFP_KERNEL);
0280     if (!dd)
0281         return -ENOMEM;
0282 
0283     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0284     if (res == NULL) {
0285         dev_err(_dev, "no MEM specified\n");
0286         ret = -ENXIO;
0287         goto exit_mem;
0288     }
0289 
0290     size = resource_size(res);
0291     spacing = size / 3;
0292 
0293     dd->io = request_mem_region(res->start, size, pdev->name);
0294     if (dd->io == NULL) {
0295         dev_err(_dev, "cannot reserve memory\n");
0296         ret = -ENXIO;
0297         goto exit_mem;
0298     }
0299 
0300     dd->base = ioremap(res->start, size);
0301     if (dd->base == NULL) {
0302         dev_err(_dev, "cannot ioremap region\n");
0303         ret = -ENXIO;
0304         goto exit_res;
0305     }
0306 
0307     irq = platform_get_irq(pdev, 0);
0308     if (irq <= 0)
0309         irq = PARPORT_IRQ_NONE;
0310 
0311     pp = parport_register_port((unsigned long)dd->base, irq,
0312                    PARPORT_DMA_NONE,
0313                    &parport_ax88796_ops);
0314 
0315     if (pp == NULL) {
0316         dev_err(_dev, "failed to register parallel port\n");
0317         ret = -ENOMEM;
0318         goto exit_unmap;
0319     }
0320 
0321     pp->private_data = dd;
0322     dd->parport = pp;
0323     dd->dev = _dev;
0324 
0325     dd->spp_data = dd->base;
0326     dd->spp_spr  = dd->base + (spacing * 1);
0327     dd->spp_cpr  = dd->base + (spacing * 2);
0328 
0329     /* initialise the port controls */
0330     writeb(AX_CPR_STRB, dd->spp_cpr);
0331 
0332     if (irq >= 0) {
0333         /* request irq */
0334         ret = request_irq(irq, parport_irq_handler,
0335                   IRQF_TRIGGER_FALLING, pdev->name, pp);
0336 
0337         if (ret < 0)
0338             goto exit_port;
0339 
0340         dd->irq_enabled = 1;
0341     }
0342 
0343     platform_set_drvdata(pdev, pp);
0344 
0345     dev_info(_dev, "attached parallel port driver\n");
0346     parport_announce_port(pp);
0347 
0348     return 0;
0349 
0350  exit_port:
0351     parport_remove_port(pp);
0352  exit_unmap:
0353     iounmap(dd->base);
0354  exit_res:
0355     release_mem_region(dd->io->start, size);
0356  exit_mem:
0357     kfree(dd);
0358     return ret;
0359 }
0360 
0361 static int parport_ax88796_remove(struct platform_device *pdev)
0362 {
0363     struct parport *p = platform_get_drvdata(pdev);
0364     struct ax_drvdata *dd = pp_to_drv(p);
0365 
0366     free_irq(p->irq, p);
0367     parport_remove_port(p);
0368     iounmap(dd->base);
0369     release_mem_region(dd->io->start, resource_size(dd->io));
0370     kfree(dd);
0371 
0372     return 0;
0373 }
0374 
0375 #ifdef CONFIG_PM
0376 
0377 static int parport_ax88796_suspend(struct platform_device *dev,
0378                    pm_message_t state)
0379 {
0380     struct parport *p = platform_get_drvdata(dev);
0381     struct ax_drvdata *dd = pp_to_drv(p);
0382 
0383     parport_ax88796_save_state(p, &dd->suspend);
0384     writeb(AX_CPR_nDOE | AX_CPR_STRB, dd->spp_cpr);
0385     return 0;
0386 }
0387 
0388 static int parport_ax88796_resume(struct platform_device *dev)
0389 {
0390     struct parport *p = platform_get_drvdata(dev);
0391     struct ax_drvdata *dd = pp_to_drv(p);
0392 
0393     parport_ax88796_restore_state(p, &dd->suspend);
0394     return 0;
0395 }
0396 
0397 #else
0398 #define parport_ax88796_suspend NULL
0399 #define parport_ax88796_resume  NULL
0400 #endif
0401 
0402 MODULE_ALIAS("platform:ax88796-pp");
0403 
0404 static struct platform_driver axdrv = {
0405     .driver     = {
0406         .name   = "ax88796-pp",
0407     },
0408     .probe      = parport_ax88796_probe,
0409     .remove     = parport_ax88796_remove,
0410     .suspend    = parport_ax88796_suspend,
0411     .resume     = parport_ax88796_resume,
0412 };
0413 
0414 module_platform_driver(axdrv);
0415 
0416 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
0417 MODULE_DESCRIPTION("AX88796 Parport parallel port driver");
0418 MODULE_LICENSE("GPL");