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