aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia
diff options
context:
space:
mode:
authorRussell King - ARM Linux <linux@arm.linux.org.uk>2009-03-26 17:45:05 -0400
committerDominik Brodowski <linux@dominikbrodowski.net>2009-11-09 02:30:09 -0500
commit097e296d6175881eba7244de7222de61e9569911 (patch)
tree7202f0cc53dd48fd9e2ec14cd5751311d1f5d2d3 /drivers/pcmcia
parent0f767de6a26a07f7d58394512b6f6c96322f047f (diff)
PCMCIA: soc_common: provide single socket add/remove functionality
Factor out the functionality for adding and removing a single socket, thereby allowing SoCs to individually register each socket. The advantage of this approach is that SoCs can then extend soc_pcmcia_socket as they wish. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r--drivers/pcmcia/soc_common.c230
-rw-r--r--drivers/pcmcia/soc_common.h3
2 files changed, 125 insertions, 108 deletions
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index a2d448f20b0f..9bfa74a6d8ff 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -574,7 +574,7 @@ void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt,
574EXPORT_SYMBOL(soc_pcmcia_enable_irqs); 574EXPORT_SYMBOL(soc_pcmcia_enable_irqs);
575 575
576 576
577LIST_HEAD(soc_pcmcia_sockets); 577static LIST_HEAD(soc_pcmcia_sockets);
578static DEFINE_MUTEX(soc_pcmcia_sockets_lock); 578static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
579 579
580#ifdef CONFIG_CPU_FREQ 580#ifdef CONFIG_CPU_FREQ
@@ -619,158 +619,174 @@ module_exit(soc_pcmcia_cpufreq_unregister);
619 619
620#endif 620#endif
621 621
622int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, 622void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
623 struct skt_dev_info *sinfo)
624{ 623{
625 struct soc_pcmcia_socket *skt;
626 int ret, i;
627
628 mutex_lock(&soc_pcmcia_sockets_lock); 624 mutex_lock(&soc_pcmcia_sockets_lock);
625 del_timer_sync(&skt->poll_timer);
629 626
630 /* 627 pcmcia_unregister_socket(&skt->socket);
631 * Initialise the per-socket structure.
632 */
633 for (i = 0; i < sinfo->nskt; i++) {
634 skt = &sinfo->skt[i];
635 628
636 skt->socket.ops = &soc_common_pcmcia_operations; 629 flush_scheduled_work();
637 skt->socket.owner = ops->owner;
638 skt->socket.dev.parent = dev;
639 630
640 init_timer(&skt->poll_timer); 631 skt->ops->hw_shutdown(skt);
641 skt->poll_timer.function = soc_common_pcmcia_poll_event;
642 skt->poll_timer.data = (unsigned long)skt;
643 skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
644 632
645 skt->dev = dev; 633 soc_common_pcmcia_config_skt(skt, &dead_socket);
646 skt->ops = ops;
647 634
648 ret = request_resource(&iomem_resource, &skt->res_skt); 635 list_del(&skt->node);
649 if (ret) 636 mutex_unlock(&soc_pcmcia_sockets_lock);
650 goto out_err_1;
651 637
652 ret = request_resource(&skt->res_skt, &skt->res_io); 638 iounmap(skt->virt_io);
653 if (ret) 639 skt->virt_io = NULL;
654 goto out_err_2; 640 release_resource(&skt->res_attr);
641 release_resource(&skt->res_mem);
642 release_resource(&skt->res_io);
643 release_resource(&skt->res_skt);
644}
645EXPORT_SYMBOL(soc_pcmcia_remove_one);
655 646
656 ret = request_resource(&skt->res_skt, &skt->res_mem); 647int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
657 if (ret) 648{
658 goto out_err_3; 649 int ret;
659 650
660 ret = request_resource(&skt->res_skt, &skt->res_attr); 651 init_timer(&skt->poll_timer);
661 if (ret) 652 skt->poll_timer.function = soc_common_pcmcia_poll_event;
662 goto out_err_4; 653 skt->poll_timer.data = (unsigned long)skt;
654 skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
663 655
664 skt->virt_io = ioremap(skt->res_io.start, 0x10000); 656 ret = request_resource(&iomem_resource, &skt->res_skt);
665 if (skt->virt_io == NULL) { 657 if (ret)
666 ret = -ENOMEM; 658 goto out_err_1;
667 goto out_err_5;
668 }
669 659
670 list_add(&skt->node, &soc_pcmcia_sockets); 660 ret = request_resource(&skt->res_skt, &skt->res_io);
661 if (ret)
662 goto out_err_2;
671 663
672 /* 664 ret = request_resource(&skt->res_skt, &skt->res_mem);
673 * We initialize default socket timing here, because 665 if (ret)
674 * we are not guaranteed to see a SetIOMap operation at 666 goto out_err_3;
675 * runtime.
676 */
677 ops->set_timing(skt);
678 667
679 ret = ops->hw_init(skt); 668 ret = request_resource(&skt->res_skt, &skt->res_attr);
680 if (ret) 669 if (ret)
681 goto out_err_6; 670 goto out_err_4;
682 671
683 skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; 672 skt->virt_io = ioremap(skt->res_io.start, 0x10000);
684 skt->socket.resource_ops = &pccard_static_ops; 673 if (skt->virt_io == NULL) {
685 skt->socket.irq_mask = 0; 674 ret = -ENOMEM;
686 skt->socket.map_size = PAGE_SIZE; 675 goto out_err_5;
687 skt->socket.pci_irq = skt->irq; 676 }
688 skt->socket.io_offset = (unsigned long)skt->virt_io;
689 677
690 skt->status = soc_common_pcmcia_skt_state(skt); 678 mutex_lock(&soc_pcmcia_sockets_lock);
691 679
692 ret = pcmcia_register_socket(&skt->socket); 680 list_add(&skt->node, &soc_pcmcia_sockets);
693 if (ret)
694 goto out_err_7;
695 681
696 WARN_ON(skt->socket.sock != i); 682 /*
683 * We initialize default socket timing here, because
684 * we are not guaranteed to see a SetIOMap operation at
685 * runtime.
686 */
687 skt->ops->set_timing(skt);
697 688
698 add_timer(&skt->poll_timer); 689 ret = skt->ops->hw_init(skt);
690 if (ret)
691 goto out_err_6;
699 692
700 ret = device_create_file(&skt->socket.dev, &dev_attr_status); 693 skt->socket.ops = &soc_common_pcmcia_operations;
701 if (ret) 694 skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
702 goto out_err_8; 695 skt->socket.resource_ops = &pccard_static_ops;
703 } 696 skt->socket.irq_mask = 0;
697 skt->socket.map_size = PAGE_SIZE;
698 skt->socket.pci_irq = skt->irq;
699 skt->socket.io_offset = (unsigned long)skt->virt_io;
704 700
705 dev_set_drvdata(dev, sinfo); 701 skt->status = soc_common_pcmcia_skt_state(skt);
706 ret = 0;
707 goto out;
708 702
709 do { 703 ret = pcmcia_register_socket(&skt->socket);
710 skt = &sinfo->skt[i]; 704 if (ret)
705 goto out_err_7;
706
707 add_timer(&skt->poll_timer);
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;
711 716
712 device_remove_file(&skt->socket.dev, &dev_attr_status);
713 out_err_8: 717 out_err_8:
714 del_timer_sync(&skt->poll_timer); 718 mutex_lock(&soc_pcmcia_sockets_lock);
715 pcmcia_unregister_socket(&skt->socket); 719 del_timer_sync(&skt->poll_timer);
720 pcmcia_unregister_socket(&skt->socket);
716 721
717 out_err_7: 722 out_err_7:
718 flush_scheduled_work(); 723 flush_scheduled_work();
719 724
720 ops->hw_shutdown(skt); 725 skt->ops->hw_shutdown(skt);
721 out_err_6: 726 out_err_6:
722 list_del(&skt->node); 727 list_del(&skt->node);
723 iounmap(skt->virt_io); 728 mutex_unlock(&soc_pcmcia_sockets_lock);
729 iounmap(skt->virt_io);
724 out_err_5: 730 out_err_5:
725 release_resource(&skt->res_attr); 731 release_resource(&skt->res_attr);
726 out_err_4: 732 out_err_4:
727 release_resource(&skt->res_mem); 733 release_resource(&skt->res_mem);
728 out_err_3: 734 out_err_3:
729 release_resource(&skt->res_io); 735 release_resource(&skt->res_io);
730 out_err_2: 736 out_err_2:
731 release_resource(&skt->res_skt); 737 release_resource(&skt->res_skt);
732 out_err_1: 738 out_err_1:
733 i--;
734 } while (i > 0);
735 739
736 kfree(sinfo);
737
738 out:
739 mutex_unlock(&soc_pcmcia_sockets_lock);
740 return ret; 740 return ret;
741} 741}
742EXPORT_SYMBOL(soc_common_drv_pcmcia_probe); 742EXPORT_SYMBOL(soc_pcmcia_add_one);
743 743
744int soc_common_drv_pcmcia_remove(struct device *dev) 744int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
745 struct skt_dev_info *sinfo)
745{ 746{
746 struct skt_dev_info *sinfo = dev_get_drvdata(dev); 747 struct soc_pcmcia_socket *skt;
747 int i; 748 int ret, i;
748 749
749 dev_set_drvdata(dev, NULL); 750 /*
751 * Initialise the per-socket structure.
752 */
753 for (i = ret = 0; i < sinfo->nskt; i++) {
754 skt = &sinfo->skt[i];
750 755
751 mutex_lock(&soc_pcmcia_sockets_lock); 756 skt->socket.owner = ops->owner;
752 for (i = 0; i < sinfo->nskt; i++) { 757 skt->socket.dev.parent = dev;
753 struct soc_pcmcia_socket *skt = &sinfo->skt[i];
754 758
755 del_timer_sync(&skt->poll_timer); 759 skt->dev = dev;
760 skt->ops = ops;
756 761
757 pcmcia_unregister_socket(&skt->socket); 762 ret = soc_pcmcia_add_one(skt);
763 if (ret)
764 break;
758 765
759 flush_scheduled_work(); 766 WARN_ON(skt->socket.sock != i);
767 }
760 768
761 skt->ops->hw_shutdown(skt); 769 if (ret) {
770 while (--i >= 0)
771 soc_pcmcia_remove_one(&sinfo->skt[i]);
772 kfree(sinfo);
773 } else {
774 dev_set_drvdata(dev, sinfo);
775 }
762 776
763 soc_common_pcmcia_config_skt(skt, &dead_socket); 777 return ret;
778}
779EXPORT_SYMBOL(soc_common_drv_pcmcia_probe);
764 780
765 list_del(&skt->node); 781int soc_common_drv_pcmcia_remove(struct device *dev)
766 iounmap(skt->virt_io); 782{
767 skt->virt_io = NULL; 783 struct skt_dev_info *sinfo = dev_get_drvdata(dev);
768 release_resource(&skt->res_attr); 784 int i;
769 release_resource(&skt->res_mem); 785
770 release_resource(&skt->res_io); 786 dev_set_drvdata(dev, NULL);
771 release_resource(&skt->res_skt); 787
772 } 788 for (i = 0; i < sinfo->nskt; i++)
773 mutex_unlock(&soc_pcmcia_sockets_lock); 789 soc_pcmcia_remove_one(&sinfo->skt[i]);
774 790
775 kfree(sinfo); 791 kfree(sinfo);
776 792
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 290e143839ee..51c72bae018e 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -135,7 +135,8 @@ extern void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_
135extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *); 135extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *);
136 136
137 137
138extern struct list_head soc_pcmcia_sockets; 138void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt);
139int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt);
139 140
140extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct skt_dev_info *sinfo); 141extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct skt_dev_info *sinfo);
141extern int soc_common_drv_pcmcia_remove(struct device *dev); 142extern int soc_common_drv_pcmcia_remove(struct device *dev);