Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] AX88796 parallel port driver

Driver for the simple parallel port interface on the Asix AX88796 chip on
an platform_bus.

[akpm@osdl.org: x86_64 build fix]
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Ben Dooks and committed by
Linus Torvalds
ad4063b0 11e64757

+461
+12
drivers/parport/Kconfig
··· 136 136 found on many Sun machines. Note that many of the newer Ultras 137 137 actually have pc style hardware instead. 138 138 139 + config PARPORT_AX88796 140 + tristate "AX88796 Parallel Port" 141 + depends on PARPORT 142 + select PARPORT_NOT_PC 143 + help 144 + Say Y here if you need support for the parallel port hardware on 145 + the AX88796 network controller chip. This code is also available 146 + as a module (say M), called parport_ax88796. 147 + 148 + The driver is not dependant on the AX88796 network driver, and 149 + should not interfere with the networking functions of the chip. 150 + 139 151 config PARPORT_1284 140 152 bool "IEEE 1284 transfer modes" 141 153 depends on PARPORT
+1
drivers/parport/Makefile
··· 17 17 obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o 18 18 obj-$(CONFIG_PARPORT_SUNBPP) += parport_sunbpp.o 19 19 obj-$(CONFIG_PARPORT_GSC) += parport_gsc.o 20 + obj-$(CONFIG_PARPORT_AX88796) += parport_ax88796.o 20 21 obj-$(CONFIG_PARPORT_IP32) += parport_ip32.o
+443
drivers/parport/parport_ax88796.c
··· 1 + /* linux/drivers/parport/parport_ax88796.c 2 + * 3 + * (c) 2005,2006 Simtec Electronics 4 + * Ben Dooks <ben@simtec.co.uk> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + */ 11 + 12 + #include <linux/module.h> 13 + #include <linux/kernel.h> 14 + #include <linux/parport.h> 15 + #include <linux/interrupt.h> 16 + #include <linux/errno.h> 17 + #include <linux/platform_device.h> 18 + 19 + #include <asm/io.h> 20 + #include <asm/irq.h> 21 + 22 + #define AX_SPR_BUSY (1<<7) 23 + #define AX_SPR_ACK (1<<6) 24 + #define AX_SPR_PE (1<<5) 25 + #define AX_SPR_SLCT (1<<4) 26 + #define AX_SPR_ERR (1<<3) 27 + 28 + #define AX_CPR_nDOE (1<<5) 29 + #define AX_CPR_SLCTIN (1<<3) 30 + #define AX_CPR_nINIT (1<<2) 31 + #define AX_CPR_ATFD (1<<1) 32 + #define AX_CPR_STRB (1<<0) 33 + 34 + struct ax_drvdata { 35 + struct parport *parport; 36 + struct parport_state suspend; 37 + 38 + struct device *dev; 39 + struct resource *io; 40 + 41 + unsigned char irq_enabled; 42 + 43 + void __iomem *base; 44 + void __iomem *spp_data; 45 + void __iomem *spp_spr; 46 + void __iomem *spp_cpr; 47 + }; 48 + 49 + static inline struct ax_drvdata *pp_to_drv(struct parport *p) 50 + { 51 + return p->private_data; 52 + } 53 + 54 + static unsigned char 55 + parport_ax88796_read_data(struct parport *p) 56 + { 57 + struct ax_drvdata *dd = pp_to_drv(p); 58 + 59 + return readb(dd->spp_data); 60 + } 61 + 62 + static void 63 + parport_ax88796_write_data(struct parport *p, unsigned char data) 64 + { 65 + struct ax_drvdata *dd = pp_to_drv(p); 66 + 67 + writeb(data, dd->spp_data); 68 + } 69 + 70 + static unsigned char 71 + parport_ax88796_read_control(struct parport *p) 72 + { 73 + struct ax_drvdata *dd = pp_to_drv(p); 74 + unsigned int cpr = readb(dd->spp_cpr); 75 + unsigned int ret = 0; 76 + 77 + if (!(cpr & AX_CPR_STRB)) 78 + ret |= PARPORT_CONTROL_STROBE; 79 + 80 + if (!(cpr & AX_CPR_ATFD)) 81 + ret |= PARPORT_CONTROL_AUTOFD; 82 + 83 + if (cpr & AX_CPR_nINIT) 84 + ret |= PARPORT_CONTROL_INIT; 85 + 86 + if (!(cpr & AX_CPR_SLCTIN)) 87 + ret |= PARPORT_CONTROL_SELECT; 88 + 89 + return ret; 90 + } 91 + 92 + static void 93 + parport_ax88796_write_control(struct parport *p, unsigned char control) 94 + { 95 + struct ax_drvdata *dd = pp_to_drv(p); 96 + unsigned int cpr = readb(dd->spp_cpr); 97 + 98 + cpr &= AX_CPR_nDOE; 99 + 100 + if (!(control & PARPORT_CONTROL_STROBE)) 101 + cpr |= AX_CPR_STRB; 102 + 103 + if (!(control & PARPORT_CONTROL_AUTOFD)) 104 + cpr |= AX_CPR_ATFD; 105 + 106 + if (control & PARPORT_CONTROL_INIT) 107 + cpr |= AX_CPR_nINIT; 108 + 109 + if (!(control & PARPORT_CONTROL_SELECT)) 110 + cpr |= AX_CPR_SLCTIN; 111 + 112 + dev_dbg(dd->dev, "write_control: ctrl=%02x, cpr=%02x\n", control, cpr); 113 + writeb(cpr, dd->spp_cpr); 114 + 115 + if (parport_ax88796_read_control(p) != control) { 116 + dev_err(dd->dev, "write_control: read != set (%02x, %02x)\n", 117 + parport_ax88796_read_control(p), control); 118 + } 119 + } 120 + 121 + static unsigned char 122 + parport_ax88796_read_status(struct parport *p) 123 + { 124 + struct ax_drvdata *dd = pp_to_drv(p); 125 + unsigned int status = readb(dd->spp_spr); 126 + unsigned int ret = 0; 127 + 128 + if (status & AX_SPR_BUSY) 129 + ret |= PARPORT_STATUS_BUSY; 130 + 131 + if (status & AX_SPR_ACK) 132 + ret |= PARPORT_STATUS_ACK; 133 + 134 + if (status & AX_SPR_ERR) 135 + ret |= PARPORT_STATUS_ERROR; 136 + 137 + if (status & AX_SPR_SLCT) 138 + ret |= PARPORT_STATUS_SELECT; 139 + 140 + if (status & AX_SPR_PE) 141 + ret |= PARPORT_STATUS_PAPEROUT; 142 + 143 + return ret; 144 + } 145 + 146 + static unsigned char 147 + parport_ax88796_frob_control(struct parport *p, unsigned char mask, 148 + unsigned char val) 149 + { 150 + struct ax_drvdata *dd = pp_to_drv(p); 151 + unsigned char old = parport_ax88796_read_control(p); 152 + 153 + dev_dbg(dd->dev, "frob: mask=%02x, val=%02x, old=%02x\n", 154 + mask, val, old); 155 + 156 + parport_ax88796_write_control(p, (old & ~mask) | val); 157 + return old; 158 + } 159 + 160 + static void 161 + parport_ax88796_enable_irq(struct parport *p) 162 + { 163 + struct ax_drvdata *dd = pp_to_drv(p); 164 + unsigned long flags; 165 + 166 + local_irq_save(flags); 167 + if (!dd->irq_enabled) { 168 + enable_irq(p->irq); 169 + dd->irq_enabled = 1; 170 + } 171 + local_irq_restore(flags); 172 + } 173 + 174 + static void 175 + parport_ax88796_disable_irq(struct parport *p) 176 + { 177 + struct ax_drvdata *dd = pp_to_drv(p); 178 + unsigned long flags; 179 + 180 + local_irq_save(flags); 181 + if (dd->irq_enabled) { 182 + disable_irq(p->irq); 183 + dd->irq_enabled = 0; 184 + } 185 + local_irq_restore(flags); 186 + } 187 + 188 + static void 189 + parport_ax88796_data_forward(struct parport *p) 190 + { 191 + struct ax_drvdata *dd = pp_to_drv(p); 192 + void __iomem *cpr = dd->spp_cpr; 193 + 194 + writeb((readb(cpr) & ~AX_CPR_nDOE), cpr); 195 + } 196 + 197 + static void 198 + parport_ax88796_data_reverse(struct parport *p) 199 + { 200 + struct ax_drvdata *dd = pp_to_drv(p); 201 + void __iomem *cpr = dd->spp_cpr; 202 + 203 + writeb(readb(cpr) | AX_CPR_nDOE, cpr); 204 + } 205 + 206 + static void 207 + parport_ax88796_init_state(struct pardevice *d, struct parport_state *s) 208 + { 209 + struct ax_drvdata *dd = pp_to_drv(d->port); 210 + 211 + memset(s, 0, sizeof(struct parport_state)); 212 + 213 + dev_dbg(dd->dev, "init_state: %p: state=%p\n", d, s); 214 + s->u.ax88796.cpr = readb(dd->spp_cpr); 215 + } 216 + 217 + static void 218 + parport_ax88796_save_state(struct parport *p, struct parport_state *s) 219 + { 220 + struct ax_drvdata *dd = pp_to_drv(p); 221 + 222 + dev_dbg(dd->dev, "save_state: %p: state=%p\n", p, s); 223 + s->u.ax88796.cpr = readb(dd->spp_cpr); 224 + } 225 + 226 + static void 227 + parport_ax88796_restore_state(struct parport *p, struct parport_state *s) 228 + { 229 + struct ax_drvdata *dd = pp_to_drv(p); 230 + 231 + dev_dbg(dd->dev, "restore_state: %p: state=%p\n", p, s); 232 + writeb(s->u.ax88796.cpr, dd->spp_cpr); 233 + } 234 + 235 + static irqreturn_t 236 + parport_ax88796_interrupt(int irq, void *dev_id, struct pt_regs *regs) 237 + { 238 + parport_generic_irq(irq, dev_id, regs); 239 + return IRQ_HANDLED; 240 + } 241 + 242 + 243 + static struct parport_operations parport_ax88796_ops = { 244 + .write_data = parport_ax88796_write_data, 245 + .read_data = parport_ax88796_read_data, 246 + 247 + .write_control = parport_ax88796_write_control, 248 + .read_control = parport_ax88796_read_control, 249 + .frob_control = parport_ax88796_frob_control, 250 + 251 + .read_status = parport_ax88796_read_status, 252 + 253 + .enable_irq = parport_ax88796_enable_irq, 254 + .disable_irq = parport_ax88796_disable_irq, 255 + 256 + .data_forward = parport_ax88796_data_forward, 257 + .data_reverse = parport_ax88796_data_reverse, 258 + 259 + .init_state = parport_ax88796_init_state, 260 + .save_state = parport_ax88796_save_state, 261 + .restore_state = parport_ax88796_restore_state, 262 + 263 + .epp_write_data = parport_ieee1284_epp_write_data, 264 + .epp_read_data = parport_ieee1284_epp_read_data, 265 + .epp_write_addr = parport_ieee1284_epp_write_addr, 266 + .epp_read_addr = parport_ieee1284_epp_read_addr, 267 + 268 + .ecp_write_data = parport_ieee1284_ecp_write_data, 269 + .ecp_read_data = parport_ieee1284_ecp_read_data, 270 + .ecp_write_addr = parport_ieee1284_ecp_write_addr, 271 + 272 + .compat_write_data = parport_ieee1284_write_compat, 273 + .nibble_read_data = parport_ieee1284_read_nibble, 274 + .byte_read_data = parport_ieee1284_read_byte, 275 + 276 + .owner = THIS_MODULE, 277 + }; 278 + 279 + static int parport_ax88796_probe(struct platform_device *pdev) 280 + { 281 + struct device *_dev = &pdev->dev; 282 + struct ax_drvdata *dd; 283 + struct parport *pp = NULL; 284 + struct resource *res; 285 + unsigned long size; 286 + int spacing; 287 + int irq; 288 + int ret; 289 + 290 + dd = kzalloc(sizeof(struct ax_drvdata), GFP_KERNEL); 291 + if (dd == NULL) { 292 + dev_err(_dev, "no memory for private data\n"); 293 + return -ENOMEM; 294 + } 295 + 296 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 297 + if (res == NULL) { 298 + dev_err(_dev, "no MEM specified\n"); 299 + ret = -ENXIO; 300 + goto exit_mem; 301 + } 302 + 303 + size = (res->end - res->start) + 1; 304 + spacing = size / 3; 305 + 306 + dd->io = request_mem_region(res->start, size, pdev->name); 307 + if (dd->io == NULL) { 308 + dev_err(_dev, "cannot reserve memory\n"); 309 + ret = -ENXIO; 310 + goto exit_mem; 311 + } 312 + 313 + dd->base = ioremap(res->start, size); 314 + if (dd->base == NULL) { 315 + dev_err(_dev, "cannot ioremap region\n"); 316 + ret = -ENXIO; 317 + goto exit_res; 318 + } 319 + 320 + irq = platform_get_irq(pdev, 0); 321 + if (irq <= 0) 322 + irq = PARPORT_IRQ_NONE; 323 + 324 + pp = parport_register_port((unsigned long)dd->base, irq, 325 + PARPORT_DMA_NONE, 326 + &parport_ax88796_ops); 327 + 328 + if (pp == NULL) { 329 + dev_err(_dev, "failed to register parallel port\n"); 330 + ret = -ENOMEM; 331 + goto exit_unmap; 332 + } 333 + 334 + pp->private_data = dd; 335 + dd->parport = pp; 336 + dd->dev = _dev; 337 + 338 + dd->spp_data = dd->base; 339 + dd->spp_spr = dd->base + (spacing * 1); 340 + dd->spp_cpr = dd->base + (spacing * 2); 341 + 342 + /* initialise the port controls */ 343 + writeb(AX_CPR_STRB, dd->spp_cpr); 344 + 345 + if (irq >= 0) { 346 + /* request irq */ 347 + ret = request_irq(irq, parport_ax88796_interrupt, 348 + SA_TRIGGER_FALLING, pdev->name, pp); 349 + 350 + if (ret < 0) 351 + goto exit_port; 352 + 353 + dd->irq_enabled = 1; 354 + } 355 + 356 + platform_set_drvdata(pdev, pp); 357 + 358 + dev_info(_dev, "attached parallel port driver\n"); 359 + parport_announce_port(pp); 360 + 361 + return 0; 362 + 363 + exit_port: 364 + parport_remove_port(pp); 365 + exit_unmap: 366 + iounmap(dd->base); 367 + exit_res: 368 + release_resource(dd->io); 369 + kfree(dd->io); 370 + exit_mem: 371 + kfree(dd); 372 + return ret; 373 + } 374 + 375 + static int parport_ax88796_remove(struct platform_device *pdev) 376 + { 377 + struct parport *p = platform_get_drvdata(pdev); 378 + struct ax_drvdata *dd = pp_to_drv(p); 379 + 380 + free_irq(p->irq, p); 381 + parport_remove_port(p); 382 + iounmap(dd->base); 383 + release_resource(dd->io); 384 + kfree(dd->io); 385 + kfree(dd); 386 + 387 + return 0; 388 + } 389 + 390 + #ifdef CONFIG_PM 391 + 392 + static int parport_ax88796_suspend(struct platform_device *dev, 393 + pm_message_t state) 394 + { 395 + struct parport *p = platform_get_drvdata(dev); 396 + struct ax_drvdata *dd = pp_to_drv(p); 397 + 398 + parport_ax88796_save_state(p, &dd->suspend); 399 + writeb(AX_CPR_nDOE | AX_CPR_STRB, dd->spp_cpr); 400 + return 0; 401 + } 402 + 403 + static int parport_ax88796_resume(struct platform_device *dev) 404 + { 405 + struct parport *p = platform_get_drvdata(dev); 406 + struct ax_drvdata *dd = pp_to_drv(p); 407 + 408 + parport_ax88796_restore_state(p, &dd->suspend); 409 + return 0; 410 + } 411 + 412 + #else 413 + #define parport_ax88796_suspend NULL 414 + #define parport_ax88796_resume NULL 415 + #endif 416 + 417 + static struct platform_driver axdrv = { 418 + .driver = { 419 + .name = "ax88796-pp", 420 + .owner = THIS_MODULE, 421 + }, 422 + .probe = parport_ax88796_probe, 423 + .remove = parport_ax88796_remove, 424 + .suspend = parport_ax88796_suspend, 425 + .resume = parport_ax88796_resume, 426 + }; 427 + 428 + static int __init parport_ax88796_init(void) 429 + { 430 + return platform_driver_register(&axdrv); 431 + } 432 + 433 + static void __exit parport_ax88796_exit(void) 434 + { 435 + platform_driver_unregister(&axdrv); 436 + } 437 + 438 + module_init(parport_ax88796_init) 439 + module_exit(parport_ax88796_exit) 440 + 441 + MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 442 + MODULE_DESCRIPTION("AX88796 Parport parallel port driver"); 443 + MODULE_LICENSE("GPL");
+5
include/linux/parport.h
··· 127 127 unsigned char statusdir;/* ciab.ddrb & 7 */ 128 128 }; 129 129 130 + struct ax88796_parport_state { 131 + unsigned char cpr; 132 + }; 133 + 130 134 struct ip32_parport_state { 131 135 unsigned int dcr; 132 136 unsigned int ecr; ··· 142 138 /* ARC has no state. */ 143 139 struct ax_parport_state ax; 144 140 struct amiga_parport_state amiga; 141 + struct ax88796_parport_state ax88796; 145 142 /* Atari has not state. */ 146 143 struct ip32_parport_state ip32; 147 144 void *misc;