diff options
Diffstat (limited to 'drivers/pcmcia/soc_common.c')
-rw-r--r-- | drivers/pcmcia/soc_common.c | 225 |
1 files changed, 93 insertions, 132 deletions
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index ef7e9e58782b..6f1a86b43c60 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c | |||
@@ -144,10 +144,10 @@ soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *stat | |||
144 | */ | 144 | */ |
145 | if (skt->irq_state != 1 && state->io_irq) { | 145 | if (skt->irq_state != 1 && state->io_irq) { |
146 | skt->irq_state = 1; | 146 | skt->irq_state = 1; |
147 | set_irq_type(skt->irq, IRQ_TYPE_EDGE_FALLING); | 147 | set_irq_type(skt->socket.pci_irq, IRQ_TYPE_EDGE_FALLING); |
148 | } else if (skt->irq_state == 1 && state->io_irq == 0) { | 148 | } else if (skt->irq_state == 1 && state->io_irq == 0) { |
149 | skt->irq_state = 0; | 149 | skt->irq_state = 0; |
150 | set_irq_type(skt->irq, IRQ_TYPE_NONE); | 150 | set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE); |
151 | } | 151 | } |
152 | 152 | ||
153 | skt->cs_state = *state; | 153 | skt->cs_state = *state; |
@@ -492,7 +492,8 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, ch | |||
492 | 492 | ||
493 | p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); | 493 | p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); |
494 | p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); | 494 | p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); |
495 | p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, skt->irq); | 495 | p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, |
496 | skt->socket.pci_irq); | ||
496 | if (skt->ops->show_timing) | 497 | if (skt->ops->show_timing) |
497 | p+=skt->ops->show_timing(skt, p); | 498 | p+=skt->ops->show_timing(skt, p); |
498 | 499 | ||
@@ -574,7 +575,7 @@ void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, | |||
574 | EXPORT_SYMBOL(soc_pcmcia_enable_irqs); | 575 | EXPORT_SYMBOL(soc_pcmcia_enable_irqs); |
575 | 576 | ||
576 | 577 | ||
577 | LIST_HEAD(soc_pcmcia_sockets); | 578 | static LIST_HEAD(soc_pcmcia_sockets); |
578 | static DEFINE_MUTEX(soc_pcmcia_sockets_lock); | 579 | static DEFINE_MUTEX(soc_pcmcia_sockets_lock); |
579 | 580 | ||
580 | #ifdef CONFIG_CPU_FREQ | 581 | #ifdef CONFIG_CPU_FREQ |
@@ -609,177 +610,137 @@ static int soc_pcmcia_cpufreq_register(void) | |||
609 | "notifier for PCMCIA (%d)\n", ret); | 610 | "notifier for PCMCIA (%d)\n", ret); |
610 | return ret; | 611 | return ret; |
611 | } | 612 | } |
613 | fs_initcall(soc_pcmcia_cpufreq_register); | ||
612 | 614 | ||
613 | static void soc_pcmcia_cpufreq_unregister(void) | 615 | static void soc_pcmcia_cpufreq_unregister(void) |
614 | { | 616 | { |
615 | cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); | 617 | cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); |
616 | } | 618 | } |
619 | module_exit(soc_pcmcia_cpufreq_unregister); | ||
617 | 620 | ||
618 | #else | ||
619 | static int soc_pcmcia_cpufreq_register(void) { return 0; } | ||
620 | static void soc_pcmcia_cpufreq_unregister(void) {} | ||
621 | #endif | 621 | #endif |
622 | 622 | ||
623 | int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, | 623 | void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt) |
624 | struct skt_dev_info *sinfo) | ||
625 | { | 624 | { |
626 | struct soc_pcmcia_socket *skt; | ||
627 | int ret, i; | ||
628 | |||
629 | mutex_lock(&soc_pcmcia_sockets_lock); | 625 | mutex_lock(&soc_pcmcia_sockets_lock); |
626 | del_timer_sync(&skt->poll_timer); | ||
630 | 627 | ||
631 | /* | 628 | pcmcia_unregister_socket(&skt->socket); |
632 | * Initialise the per-socket structure. | ||
633 | */ | ||
634 | for (i = 0; i < sinfo->nskt; i++) { | ||
635 | skt = &sinfo->skt[i]; | ||
636 | 629 | ||
637 | skt->socket.ops = &soc_common_pcmcia_operations; | 630 | flush_scheduled_work(); |
638 | skt->socket.owner = ops->owner; | ||
639 | skt->socket.dev.parent = dev; | ||
640 | 631 | ||
641 | init_timer(&skt->poll_timer); | 632 | skt->ops->hw_shutdown(skt); |
642 | skt->poll_timer.function = soc_common_pcmcia_poll_event; | ||
643 | skt->poll_timer.data = (unsigned long)skt; | ||
644 | skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD; | ||
645 | 633 | ||
646 | skt->dev = dev; | 634 | soc_common_pcmcia_config_skt(skt, &dead_socket); |
647 | skt->ops = ops; | ||
648 | 635 | ||
649 | ret = request_resource(&iomem_resource, &skt->res_skt); | 636 | list_del(&skt->node); |
650 | if (ret) | 637 | mutex_unlock(&soc_pcmcia_sockets_lock); |
651 | goto out_err_1; | ||
652 | 638 | ||
653 | ret = request_resource(&skt->res_skt, &skt->res_io); | 639 | iounmap(skt->virt_io); |
654 | if (ret) | 640 | skt->virt_io = NULL; |
655 | goto out_err_2; | 641 | release_resource(&skt->res_attr); |
642 | release_resource(&skt->res_mem); | ||
643 | release_resource(&skt->res_io); | ||
644 | release_resource(&skt->res_skt); | ||
645 | } | ||
646 | EXPORT_SYMBOL(soc_pcmcia_remove_one); | ||
656 | 647 | ||
657 | ret = request_resource(&skt->res_skt, &skt->res_mem); | 648 | int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) |
658 | if (ret) | 649 | { |
659 | goto out_err_3; | 650 | int ret; |
660 | 651 | ||
661 | ret = request_resource(&skt->res_skt, &skt->res_attr); | 652 | init_timer(&skt->poll_timer); |
662 | if (ret) | 653 | skt->poll_timer.function = soc_common_pcmcia_poll_event; |
663 | goto out_err_4; | 654 | skt->poll_timer.data = (unsigned long)skt; |
655 | skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD; | ||
664 | 656 | ||
665 | skt->virt_io = ioremap(skt->res_io.start, 0x10000); | 657 | ret = request_resource(&iomem_resource, &skt->res_skt); |
666 | if (skt->virt_io == NULL) { | 658 | if (ret) |
667 | ret = -ENOMEM; | 659 | goto out_err_1; |
668 | goto out_err_5; | ||
669 | } | ||
670 | 660 | ||
671 | if (list_empty(&soc_pcmcia_sockets)) | 661 | ret = request_resource(&skt->res_skt, &skt->res_io); |
672 | soc_pcmcia_cpufreq_register(); | 662 | if (ret) |
663 | goto out_err_2; | ||
673 | 664 | ||
674 | list_add(&skt->node, &soc_pcmcia_sockets); | 665 | ret = request_resource(&skt->res_skt, &skt->res_mem); |
666 | if (ret) | ||
667 | goto out_err_3; | ||
675 | 668 | ||
676 | /* | 669 | ret = request_resource(&skt->res_skt, &skt->res_attr); |
677 | * We initialize default socket timing here, because | 670 | if (ret) |
678 | * we are not guaranteed to see a SetIOMap operation at | 671 | goto out_err_4; |
679 | * runtime. | ||
680 | */ | ||
681 | ops->set_timing(skt); | ||
682 | 672 | ||
683 | ret = ops->hw_init(skt); | 673 | skt->virt_io = ioremap(skt->res_io.start, 0x10000); |
684 | if (ret) | 674 | if (skt->virt_io == NULL) { |
685 | goto out_err_6; | 675 | ret = -ENOMEM; |
676 | goto out_err_5; | ||
677 | } | ||
686 | 678 | ||
687 | skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; | 679 | mutex_lock(&soc_pcmcia_sockets_lock); |
688 | skt->socket.resource_ops = &pccard_static_ops; | ||
689 | skt->socket.irq_mask = 0; | ||
690 | skt->socket.map_size = PAGE_SIZE; | ||
691 | skt->socket.pci_irq = skt->irq; | ||
692 | skt->socket.io_offset = (unsigned long)skt->virt_io; | ||
693 | 680 | ||
694 | skt->status = soc_common_pcmcia_skt_state(skt); | 681 | list_add(&skt->node, &soc_pcmcia_sockets); |
695 | 682 | ||
696 | ret = pcmcia_register_socket(&skt->socket); | 683 | /* |
697 | if (ret) | 684 | * We initialize default socket timing here, because |
698 | goto out_err_7; | 685 | * we are not guaranteed to see a SetIOMap operation at |
686 | * runtime. | ||
687 | */ | ||
688 | skt->ops->set_timing(skt); | ||
699 | 689 | ||
700 | WARN_ON(skt->socket.sock != i); | 690 | ret = skt->ops->hw_init(skt); |
691 | if (ret) | ||
692 | goto out_err_6; | ||
701 | 693 | ||
702 | add_timer(&skt->poll_timer); | 694 | skt->socket.ops = &soc_common_pcmcia_operations; |
695 | skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; | ||
696 | skt->socket.resource_ops = &pccard_static_ops; | ||
697 | skt->socket.irq_mask = 0; | ||
698 | skt->socket.map_size = PAGE_SIZE; | ||
699 | skt->socket.io_offset = (unsigned long)skt->virt_io; | ||
703 | 700 | ||
704 | ret = device_create_file(&skt->socket.dev, &dev_attr_status); | 701 | skt->status = soc_common_pcmcia_skt_state(skt); |
705 | if (ret) | ||
706 | goto out_err_8; | ||
707 | } | ||
708 | 702 | ||
709 | dev_set_drvdata(dev, sinfo); | 703 | ret = pcmcia_register_socket(&skt->socket); |
710 | ret = 0; | 704 | if (ret) |
711 | goto out; | 705 | goto out_err_7; |
712 | 706 | ||
713 | do { | 707 | add_timer(&skt->poll_timer); |
714 | skt = &sinfo->skt[i]; | 708 | |
709 | mutex_unlock(&soc_pcmcia_sockets_lock); | ||
710 | |||
711 | ret = device_create_file(&skt->socket.dev, &dev_attr_status); | ||
712 | if (ret) | ||
713 | goto out_err_8; | ||
714 | |||
715 | return ret; | ||
715 | 716 | ||
716 | device_remove_file(&skt->socket.dev, &dev_attr_status); | ||
717 | out_err_8: | 717 | out_err_8: |
718 | del_timer_sync(&skt->poll_timer); | 718 | mutex_lock(&soc_pcmcia_sockets_lock); |
719 | pcmcia_unregister_socket(&skt->socket); | 719 | del_timer_sync(&skt->poll_timer); |
720 | pcmcia_unregister_socket(&skt->socket); | ||
720 | 721 | ||
721 | out_err_7: | 722 | out_err_7: |
722 | flush_scheduled_work(); | 723 | flush_scheduled_work(); |
723 | 724 | ||
724 | ops->hw_shutdown(skt); | 725 | skt->ops->hw_shutdown(skt); |
725 | out_err_6: | 726 | out_err_6: |
726 | list_del(&skt->node); | 727 | list_del(&skt->node); |
727 | iounmap(skt->virt_io); | 728 | mutex_unlock(&soc_pcmcia_sockets_lock); |
729 | iounmap(skt->virt_io); | ||
728 | out_err_5: | 730 | out_err_5: |
729 | release_resource(&skt->res_attr); | 731 | release_resource(&skt->res_attr); |
730 | out_err_4: | 732 | out_err_4: |
731 | release_resource(&skt->res_mem); | 733 | release_resource(&skt->res_mem); |
732 | out_err_3: | 734 | out_err_3: |
733 | release_resource(&skt->res_io); | 735 | release_resource(&skt->res_io); |
734 | out_err_2: | 736 | out_err_2: |
735 | release_resource(&skt->res_skt); | 737 | release_resource(&skt->res_skt); |
736 | out_err_1: | 738 | out_err_1: |
737 | i--; | ||
738 | } while (i > 0); | ||
739 | 739 | ||
740 | kfree(sinfo); | ||
741 | |||
742 | out: | ||
743 | mutex_unlock(&soc_pcmcia_sockets_lock); | ||
744 | return ret; | 740 | return ret; |
745 | } | 741 | } |
742 | EXPORT_SYMBOL(soc_pcmcia_add_one); | ||
746 | 743 | ||
747 | int soc_common_drv_pcmcia_remove(struct device *dev) | 744 | MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); |
748 | { | 745 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support"); |
749 | struct skt_dev_info *sinfo = dev_get_drvdata(dev); | 746 | MODULE_LICENSE("Dual MPL/GPL"); |
750 | int i; | ||
751 | |||
752 | dev_set_drvdata(dev, NULL); | ||
753 | |||
754 | mutex_lock(&soc_pcmcia_sockets_lock); | ||
755 | for (i = 0; i < sinfo->nskt; i++) { | ||
756 | struct soc_pcmcia_socket *skt = &sinfo->skt[i]; | ||
757 | |||
758 | del_timer_sync(&skt->poll_timer); | ||
759 | |||
760 | pcmcia_unregister_socket(&skt->socket); | ||
761 | |||
762 | flush_scheduled_work(); | ||
763 | |||
764 | skt->ops->hw_shutdown(skt); | ||
765 | |||
766 | soc_common_pcmcia_config_skt(skt, &dead_socket); | ||
767 | |||
768 | list_del(&skt->node); | ||
769 | iounmap(skt->virt_io); | ||
770 | skt->virt_io = NULL; | ||
771 | release_resource(&skt->res_attr); | ||
772 | release_resource(&skt->res_mem); | ||
773 | release_resource(&skt->res_io); | ||
774 | release_resource(&skt->res_skt); | ||
775 | } | ||
776 | if (list_empty(&soc_pcmcia_sockets)) | ||
777 | soc_pcmcia_cpufreq_unregister(); | ||
778 | |||
779 | mutex_unlock(&soc_pcmcia_sockets_lock); | ||
780 | |||
781 | kfree(sinfo); | ||
782 | |||
783 | return 0; | ||
784 | } | ||
785 | EXPORT_SYMBOL(soc_common_drv_pcmcia_remove); | ||