parport_ax88796.c (9274B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* linux/drivers/parport/parport_ax88796.c 3 * 4 * (c) 2005,2006 Simtec Electronics 5 * Ben Dooks <ben@simtec.co.uk> 6*/ 7 8#include <linux/module.h> 9#include <linux/kernel.h> 10#include <linux/parport.h> 11#include <linux/interrupt.h> 12#include <linux/errno.h> 13#include <linux/platform_device.h> 14#include <linux/slab.h> 15 16#include <asm/io.h> 17#include <asm/irq.h> 18 19#define AX_SPR_BUSY (1<<7) 20#define AX_SPR_ACK (1<<6) 21#define AX_SPR_PE (1<<5) 22#define AX_SPR_SLCT (1<<4) 23#define AX_SPR_ERR (1<<3) 24 25#define AX_CPR_nDOE (1<<5) 26#define AX_CPR_SLCTIN (1<<3) 27#define AX_CPR_nINIT (1<<2) 28#define AX_CPR_ATFD (1<<1) 29#define AX_CPR_STRB (1<<0) 30 31struct ax_drvdata { 32 struct parport *parport; 33 struct parport_state suspend; 34 35 struct device *dev; 36 struct resource *io; 37 38 unsigned char irq_enabled; 39 40 void __iomem *base; 41 void __iomem *spp_data; 42 void __iomem *spp_spr; 43 void __iomem *spp_cpr; 44}; 45 46static inline struct ax_drvdata *pp_to_drv(struct parport *p) 47{ 48 return p->private_data; 49} 50 51static unsigned char 52parport_ax88796_read_data(struct parport *p) 53{ 54 struct ax_drvdata *dd = pp_to_drv(p); 55 56 return readb(dd->spp_data); 57} 58 59static void 60parport_ax88796_write_data(struct parport *p, unsigned char data) 61{ 62 struct ax_drvdata *dd = pp_to_drv(p); 63 64 writeb(data, dd->spp_data); 65} 66 67static unsigned char 68parport_ax88796_read_control(struct parport *p) 69{ 70 struct ax_drvdata *dd = pp_to_drv(p); 71 unsigned int cpr = readb(dd->spp_cpr); 72 unsigned int ret = 0; 73 74 if (!(cpr & AX_CPR_STRB)) 75 ret |= PARPORT_CONTROL_STROBE; 76 77 if (!(cpr & AX_CPR_ATFD)) 78 ret |= PARPORT_CONTROL_AUTOFD; 79 80 if (cpr & AX_CPR_nINIT) 81 ret |= PARPORT_CONTROL_INIT; 82 83 if (!(cpr & AX_CPR_SLCTIN)) 84 ret |= PARPORT_CONTROL_SELECT; 85 86 return ret; 87} 88 89static void 90parport_ax88796_write_control(struct parport *p, unsigned char control) 91{ 92 struct ax_drvdata *dd = pp_to_drv(p); 93 unsigned int cpr = readb(dd->spp_cpr); 94 95 cpr &= AX_CPR_nDOE; 96 97 if (!(control & PARPORT_CONTROL_STROBE)) 98 cpr |= AX_CPR_STRB; 99 100 if (!(control & PARPORT_CONTROL_AUTOFD)) 101 cpr |= AX_CPR_ATFD; 102 103 if (control & PARPORT_CONTROL_INIT) 104 cpr |= AX_CPR_nINIT; 105 106 if (!(control & PARPORT_CONTROL_SELECT)) 107 cpr |= AX_CPR_SLCTIN; 108 109 dev_dbg(dd->dev, "write_control: ctrl=%02x, cpr=%02x\n", control, cpr); 110 writeb(cpr, dd->spp_cpr); 111 112 if (parport_ax88796_read_control(p) != control) { 113 dev_err(dd->dev, "write_control: read != set (%02x, %02x)\n", 114 parport_ax88796_read_control(p), control); 115 } 116} 117 118static unsigned char 119parport_ax88796_read_status(struct parport *p) 120{ 121 struct ax_drvdata *dd = pp_to_drv(p); 122 unsigned int status = readb(dd->spp_spr); 123 unsigned int ret = 0; 124 125 if (status & AX_SPR_BUSY) 126 ret |= PARPORT_STATUS_BUSY; 127 128 if (status & AX_SPR_ACK) 129 ret |= PARPORT_STATUS_ACK; 130 131 if (status & AX_SPR_ERR) 132 ret |= PARPORT_STATUS_ERROR; 133 134 if (status & AX_SPR_SLCT) 135 ret |= PARPORT_STATUS_SELECT; 136 137 if (status & AX_SPR_PE) 138 ret |= PARPORT_STATUS_PAPEROUT; 139 140 return ret; 141} 142 143static unsigned char 144parport_ax88796_frob_control(struct parport *p, unsigned char mask, 145 unsigned char val) 146{ 147 struct ax_drvdata *dd = pp_to_drv(p); 148 unsigned char old = parport_ax88796_read_control(p); 149 150 dev_dbg(dd->dev, "frob: mask=%02x, val=%02x, old=%02x\n", 151 mask, val, old); 152 153 parport_ax88796_write_control(p, (old & ~mask) | val); 154 return old; 155} 156 157static void 158parport_ax88796_enable_irq(struct parport *p) 159{ 160 struct ax_drvdata *dd = pp_to_drv(p); 161 unsigned long flags; 162 163 local_irq_save(flags); 164 if (!dd->irq_enabled) { 165 enable_irq(p->irq); 166 dd->irq_enabled = 1; 167 } 168 local_irq_restore(flags); 169} 170 171static void 172parport_ax88796_disable_irq(struct parport *p) 173{ 174 struct ax_drvdata *dd = pp_to_drv(p); 175 unsigned long flags; 176 177 local_irq_save(flags); 178 if (dd->irq_enabled) { 179 disable_irq(p->irq); 180 dd->irq_enabled = 0; 181 } 182 local_irq_restore(flags); 183} 184 185static void 186parport_ax88796_data_forward(struct parport *p) 187{ 188 struct ax_drvdata *dd = pp_to_drv(p); 189 void __iomem *cpr = dd->spp_cpr; 190 191 writeb((readb(cpr) & ~AX_CPR_nDOE), cpr); 192} 193 194static void 195parport_ax88796_data_reverse(struct parport *p) 196{ 197 struct ax_drvdata *dd = pp_to_drv(p); 198 void __iomem *cpr = dd->spp_cpr; 199 200 writeb(readb(cpr) | AX_CPR_nDOE, cpr); 201} 202 203static void 204parport_ax88796_init_state(struct pardevice *d, struct parport_state *s) 205{ 206 struct ax_drvdata *dd = pp_to_drv(d->port); 207 208 memset(s, 0, sizeof(struct parport_state)); 209 210 dev_dbg(dd->dev, "init_state: %p: state=%p\n", d, s); 211 s->u.ax88796.cpr = readb(dd->spp_cpr); 212} 213 214static void 215parport_ax88796_save_state(struct parport *p, struct parport_state *s) 216{ 217 struct ax_drvdata *dd = pp_to_drv(p); 218 219 dev_dbg(dd->dev, "save_state: %p: state=%p\n", p, s); 220 s->u.ax88796.cpr = readb(dd->spp_cpr); 221} 222 223static void 224parport_ax88796_restore_state(struct parport *p, struct parport_state *s) 225{ 226 struct ax_drvdata *dd = pp_to_drv(p); 227 228 dev_dbg(dd->dev, "restore_state: %p: state=%p\n", p, s); 229 writeb(s->u.ax88796.cpr, dd->spp_cpr); 230} 231 232static struct parport_operations parport_ax88796_ops = { 233 .write_data = parport_ax88796_write_data, 234 .read_data = parport_ax88796_read_data, 235 236 .write_control = parport_ax88796_write_control, 237 .read_control = parport_ax88796_read_control, 238 .frob_control = parport_ax88796_frob_control, 239 240 .read_status = parport_ax88796_read_status, 241 242 .enable_irq = parport_ax88796_enable_irq, 243 .disable_irq = parport_ax88796_disable_irq, 244 245 .data_forward = parport_ax88796_data_forward, 246 .data_reverse = parport_ax88796_data_reverse, 247 248 .init_state = parport_ax88796_init_state, 249 .save_state = parport_ax88796_save_state, 250 .restore_state = parport_ax88796_restore_state, 251 252 .epp_write_data = parport_ieee1284_epp_write_data, 253 .epp_read_data = parport_ieee1284_epp_read_data, 254 .epp_write_addr = parport_ieee1284_epp_write_addr, 255 .epp_read_addr = parport_ieee1284_epp_read_addr, 256 257 .ecp_write_data = parport_ieee1284_ecp_write_data, 258 .ecp_read_data = parport_ieee1284_ecp_read_data, 259 .ecp_write_addr = parport_ieee1284_ecp_write_addr, 260 261 .compat_write_data = parport_ieee1284_write_compat, 262 .nibble_read_data = parport_ieee1284_read_nibble, 263 .byte_read_data = parport_ieee1284_read_byte, 264 265 .owner = THIS_MODULE, 266}; 267 268static int parport_ax88796_probe(struct platform_device *pdev) 269{ 270 struct device *_dev = &pdev->dev; 271 struct ax_drvdata *dd; 272 struct parport *pp; 273 struct resource *res; 274 unsigned long size; 275 int spacing; 276 int irq; 277 int ret; 278 279 dd = kzalloc(sizeof(*dd), GFP_KERNEL); 280 if (!dd) 281 return -ENOMEM; 282 283 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 284 if (res == NULL) { 285 dev_err(_dev, "no MEM specified\n"); 286 ret = -ENXIO; 287 goto exit_mem; 288 } 289 290 size = resource_size(res); 291 spacing = size / 3; 292 293 dd->io = request_mem_region(res->start, size, pdev->name); 294 if (dd->io == NULL) { 295 dev_err(_dev, "cannot reserve memory\n"); 296 ret = -ENXIO; 297 goto exit_mem; 298 } 299 300 dd->base = ioremap(res->start, size); 301 if (dd->base == NULL) { 302 dev_err(_dev, "cannot ioremap region\n"); 303 ret = -ENXIO; 304 goto exit_res; 305 } 306 307 irq = platform_get_irq(pdev, 0); 308 if (irq <= 0) 309 irq = PARPORT_IRQ_NONE; 310 311 pp = parport_register_port((unsigned long)dd->base, irq, 312 PARPORT_DMA_NONE, 313 &parport_ax88796_ops); 314 315 if (pp == NULL) { 316 dev_err(_dev, "failed to register parallel port\n"); 317 ret = -ENOMEM; 318 goto exit_unmap; 319 } 320 321 pp->private_data = dd; 322 dd->parport = pp; 323 dd->dev = _dev; 324 325 dd->spp_data = dd->base; 326 dd->spp_spr = dd->base + (spacing * 1); 327 dd->spp_cpr = dd->base + (spacing * 2); 328 329 /* initialise the port controls */ 330 writeb(AX_CPR_STRB, dd->spp_cpr); 331 332 if (irq >= 0) { 333 /* request irq */ 334 ret = request_irq(irq, parport_irq_handler, 335 IRQF_TRIGGER_FALLING, pdev->name, pp); 336 337 if (ret < 0) 338 goto exit_port; 339 340 dd->irq_enabled = 1; 341 } 342 343 platform_set_drvdata(pdev, pp); 344 345 dev_info(_dev, "attached parallel port driver\n"); 346 parport_announce_port(pp); 347 348 return 0; 349 350 exit_port: 351 parport_remove_port(pp); 352 exit_unmap: 353 iounmap(dd->base); 354 exit_res: 355 release_mem_region(dd->io->start, size); 356 exit_mem: 357 kfree(dd); 358 return ret; 359} 360 361static int parport_ax88796_remove(struct platform_device *pdev) 362{ 363 struct parport *p = platform_get_drvdata(pdev); 364 struct ax_drvdata *dd = pp_to_drv(p); 365 366 free_irq(p->irq, p); 367 parport_remove_port(p); 368 iounmap(dd->base); 369 release_mem_region(dd->io->start, resource_size(dd->io)); 370 kfree(dd); 371 372 return 0; 373} 374 375#ifdef CONFIG_PM 376 377static int parport_ax88796_suspend(struct platform_device *dev, 378 pm_message_t state) 379{ 380 struct parport *p = platform_get_drvdata(dev); 381 struct ax_drvdata *dd = pp_to_drv(p); 382 383 parport_ax88796_save_state(p, &dd->suspend); 384 writeb(AX_CPR_nDOE | AX_CPR_STRB, dd->spp_cpr); 385 return 0; 386} 387 388static int parport_ax88796_resume(struct platform_device *dev) 389{ 390 struct parport *p = platform_get_drvdata(dev); 391 struct ax_drvdata *dd = pp_to_drv(p); 392 393 parport_ax88796_restore_state(p, &dd->suspend); 394 return 0; 395} 396 397#else 398#define parport_ax88796_suspend NULL 399#define parport_ax88796_resume NULL 400#endif 401 402MODULE_ALIAS("platform:ax88796-pp"); 403 404static struct platform_driver axdrv = { 405 .driver = { 406 .name = "ax88796-pp", 407 }, 408 .probe = parport_ax88796_probe, 409 .remove = parport_ax88796_remove, 410 .suspend = parport_ax88796_suspend, 411 .resume = parport_ax88796_resume, 412}; 413 414module_platform_driver(axdrv); 415 416MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 417MODULE_DESCRIPTION("AX88796 Parport parallel port driver"); 418MODULE_LICENSE("GPL");