Commit 93872ba21d1087cde1d5f9603f3265c1c54d471c
1 parent
1815aed5ed
Exists in
master
and in
7 other branches
[SERIAL] sunhv: Convert to of_driver layer.
Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 71 additions and 95 deletions Side-by-side Diff
drivers/serial/sunhv.c
... | ... | @@ -20,8 +20,8 @@ |
20 | 20 | |
21 | 21 | #include <asm/hypervisor.h> |
22 | 22 | #include <asm/spitfire.h> |
23 | -#include <asm/vdev.h> | |
24 | -#include <asm/oplib.h> | |
23 | +#include <asm/prom.h> | |
24 | +#include <asm/of_device.h> | |
25 | 25 | #include <asm/irq.h> |
26 | 26 | |
27 | 27 | #if defined(CONFIG_MAGIC_SYSRQ) |
28 | 28 | |
29 | 29 | |
30 | 30 | |
31 | 31 | |
32 | 32 | |
33 | 33 | |
34 | 34 | |
35 | 35 | |
36 | 36 | |
37 | 37 | |
38 | 38 | |
39 | 39 | |
40 | 40 | |
41 | 41 | |
42 | 42 | |
43 | 43 | |
44 | 44 | |
45 | 45 | |
46 | 46 | |
47 | 47 | |
48 | 48 | |
49 | 49 | |
50 | 50 | |
... | ... | @@ -407,145 +407,121 @@ |
407 | 407 | return &sunhv_console; |
408 | 408 | } |
409 | 409 | |
410 | -static int __init hv_console_compatible(char *buf, int len) | |
410 | +static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match) | |
411 | 411 | { |
412 | - while (len) { | |
413 | - int this_len; | |
414 | - | |
415 | - if (!strcmp(buf, "qcn")) | |
416 | - return 1; | |
417 | - | |
418 | - this_len = strlen(buf) + 1; | |
419 | - | |
420 | - buf += this_len; | |
421 | - len -= this_len; | |
422 | - } | |
423 | - | |
424 | - return 0; | |
425 | -} | |
426 | - | |
427 | -static unsigned int __init get_interrupt(void) | |
428 | -{ | |
429 | - struct device_node *dev_node; | |
430 | - | |
431 | - dev_node = sun4v_vdev_root->child; | |
432 | - while (dev_node != NULL) { | |
433 | - struct property *prop; | |
434 | - | |
435 | - if (strcmp(dev_node->name, "console")) | |
436 | - goto next_sibling; | |
437 | - | |
438 | - prop = of_find_property(dev_node, "compatible", NULL); | |
439 | - if (!prop) | |
440 | - goto next_sibling; | |
441 | - | |
442 | - if (hv_console_compatible(prop->value, prop->length)) | |
443 | - break; | |
444 | - | |
445 | - next_sibling: | |
446 | - dev_node = dev_node->sibling; | |
447 | - } | |
448 | - if (!dev_node) | |
449 | - return 0; | |
450 | - | |
451 | - /* Ok, the this is the OBP node for the sun4v hypervisor | |
452 | - * console device. Decode the interrupt. | |
453 | - */ | |
454 | - return sun4v_vdev_device_interrupt(dev_node); | |
455 | -} | |
456 | - | |
457 | -static int __init sunhv_init(void) | |
458 | -{ | |
459 | 412 | struct uart_port *port; |
460 | - int ret; | |
413 | + int err; | |
461 | 414 | |
462 | - if (tlb_type != hypervisor) | |
415 | + if (op->irqs[0] == 0xffffffff) | |
463 | 416 | return -ENODEV; |
464 | 417 | |
465 | - port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); | |
418 | + port = kzalloc(sizeof(struct uart_port), GFP_KERNEL); | |
466 | 419 | if (unlikely(!port)) |
467 | 420 | return -ENOMEM; |
468 | 421 | |
469 | - memset(port, 0, sizeof(struct uart_port)); | |
422 | + sunhv_port = port; | |
470 | 423 | |
471 | 424 | port->line = 0; |
472 | 425 | port->ops = &sunhv_pops; |
473 | 426 | port->type = PORT_SUNHV; |
474 | 427 | port->uartclk = ( 29491200 / 16 ); /* arbitrary */ |
475 | 428 | |
476 | - /* Set this just to make uart_configure_port() happy. */ | |
477 | 429 | port->membase = (unsigned char __iomem *) __pa(port); |
478 | 430 | |
479 | - port->irq = get_interrupt(); | |
480 | - if (!port->irq) { | |
481 | - kfree(port); | |
482 | - return -ENODEV; | |
483 | - } | |
431 | + port->irq = op->irqs[0]; | |
484 | 432 | |
433 | + port->dev = &op->dev; | |
434 | + | |
485 | 435 | sunhv_reg.minor = sunserial_current_minor; |
486 | 436 | sunhv_reg.nr = 1; |
487 | 437 | |
488 | - ret = uart_register_driver(&sunhv_reg); | |
489 | - if (ret < 0) { | |
490 | - printk(KERN_ERR "SUNHV: uart_register_driver() failed %d\n", | |
491 | - ret); | |
492 | - kfree(port); | |
438 | + err = uart_register_driver(&sunhv_reg); | |
439 | + if (err) | |
440 | + goto out_free_port; | |
493 | 441 | |
494 | - return ret; | |
495 | - } | |
496 | - | |
497 | 442 | sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; |
498 | 443 | sunserial_current_minor += 1; |
499 | 444 | |
500 | 445 | sunhv_reg.cons = SUNHV_CONSOLE(); |
501 | 446 | |
502 | - sunhv_port = port; | |
447 | + err = uart_add_one_port(&sunhv_reg, port); | |
448 | + if (err) | |
449 | + goto out_unregister_driver; | |
503 | 450 | |
504 | - ret = uart_add_one_port(&sunhv_reg, port); | |
505 | - if (ret < 0) { | |
506 | - printk(KERN_ERR "SUNHV: uart_add_one_port() failed %d\n", ret); | |
507 | - sunserial_current_minor -= 1; | |
508 | - uart_unregister_driver(&sunhv_reg); | |
509 | - kfree(port); | |
510 | - sunhv_port = NULL; | |
511 | - return -ENODEV; | |
512 | - } | |
451 | + err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port); | |
452 | + if (err) | |
453 | + goto out_remove_port; | |
513 | 454 | |
514 | - if (request_irq(port->irq, sunhv_interrupt, | |
515 | - SA_SHIRQ, "serial(sunhv)", port)) { | |
516 | - printk(KERN_ERR "sunhv: Cannot register IRQ\n"); | |
517 | - uart_remove_one_port(&sunhv_reg, port); | |
518 | - sunserial_current_minor -= 1; | |
519 | - uart_unregister_driver(&sunhv_reg); | |
520 | - kfree(port); | |
521 | - sunhv_port = NULL; | |
522 | - return -ENODEV; | |
523 | - } | |
455 | + dev_set_drvdata(&op->dev, port); | |
524 | 456 | |
525 | 457 | return 0; |
458 | + | |
459 | +out_remove_port: | |
460 | + uart_remove_one_port(&sunhv_reg, port); | |
461 | + | |
462 | +out_unregister_driver: | |
463 | + sunserial_current_minor -= 1; | |
464 | + uart_unregister_driver(&sunhv_reg); | |
465 | + | |
466 | +out_free_port: | |
467 | + kfree(port); | |
468 | + sunhv_port = NULL; | |
469 | + return err; | |
526 | 470 | } |
527 | 471 | |
528 | -static void __exit sunhv_exit(void) | |
472 | +static int __devexit hv_remove(struct of_device *dev) | |
529 | 473 | { |
530 | - struct uart_port *port = sunhv_port; | |
474 | + struct uart_port *port = dev_get_drvdata(&dev->dev); | |
531 | 475 | |
532 | - BUG_ON(!port); | |
533 | - | |
534 | 476 | free_irq(port->irq, port); |
535 | 477 | |
536 | 478 | uart_remove_one_port(&sunhv_reg, port); |
537 | - sunserial_current_minor -= 1; | |
538 | 479 | |
480 | + sunserial_current_minor -= 1; | |
539 | 481 | uart_unregister_driver(&sunhv_reg); |
540 | 482 | |
541 | - kfree(sunhv_port); | |
483 | + kfree(port); | |
542 | 484 | sunhv_port = NULL; |
485 | + | |
486 | + dev_set_drvdata(&dev->dev, NULL); | |
487 | + | |
488 | + return 0; | |
543 | 489 | } |
544 | 490 | |
491 | +static struct of_device_id hv_match[] = { | |
492 | + { | |
493 | + .name = "console", | |
494 | + .compatible = "qcn", | |
495 | + }, | |
496 | + {}, | |
497 | +}; | |
498 | +MODULE_DEVICE_TABLE(of, hv_match); | |
499 | + | |
500 | +static struct of_platform_driver hv_driver = { | |
501 | + .name = "hv", | |
502 | + .match_table = hv_match, | |
503 | + .probe = hv_probe, | |
504 | + .remove = __devexit_p(hv_remove), | |
505 | +}; | |
506 | + | |
507 | +static int __init sunhv_init(void) | |
508 | +{ | |
509 | + if (tlb_type != hypervisor) | |
510 | + return -ENODEV; | |
511 | + | |
512 | + return of_register_driver(&hv_driver, &of_bus_type); | |
513 | +} | |
514 | + | |
515 | +static void __exit sunhv_exit(void) | |
516 | +{ | |
517 | + of_unregister_driver(&hv_driver); | |
518 | +} | |
519 | + | |
545 | 520 | module_init(sunhv_init); |
546 | 521 | module_exit(sunhv_exit); |
547 | 522 | |
548 | 523 | MODULE_AUTHOR("David S. Miller"); |
549 | -MODULE_DESCRIPTION("SUN4V Hypervisor console driver") | |
524 | +MODULE_DESCRIPTION("SUN4V Hypervisor console driver"); | |
525 | +MODULE_VERSION("2.0"); | |
550 | 526 | MODULE_LICENSE("GPL"); |