diff options
Diffstat (limited to 'drivers/pcmcia/soc_common.c')
-rw-r--r-- | drivers/pcmcia/soc_common.c | 193 |
1 files changed, 127 insertions, 66 deletions
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index a0a9c2aa8d78..e0433f571962 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c | |||
@@ -32,6 +32,7 @@ | |||
32 | 32 | ||
33 | 33 | ||
34 | #include <linux/cpufreq.h> | 34 | #include <linux/cpufreq.h> |
35 | #include <linux/gpio.h> | ||
35 | #include <linux/init.h> | 36 | #include <linux/init.h> |
36 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
37 | #include <linux/io.h> | 38 | #include <linux/io.h> |
@@ -49,6 +50,8 @@ | |||
49 | 50 | ||
50 | #include "soc_common.h" | 51 | #include "soc_common.h" |
51 | 52 | ||
53 | static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev); | ||
54 | |||
52 | #ifdef CONFIG_PCMCIA_DEBUG | 55 | #ifdef CONFIG_PCMCIA_DEBUG |
53 | 56 | ||
54 | static int pc_debug; | 57 | static int pc_debug; |
@@ -104,6 +107,93 @@ void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, | |||
104 | } | 107 | } |
105 | EXPORT_SYMBOL(soc_common_pcmcia_get_timing); | 108 | EXPORT_SYMBOL(soc_common_pcmcia_get_timing); |
106 | 109 | ||
110 | static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt, | ||
111 | unsigned int nr) | ||
112 | { | ||
113 | unsigned int i; | ||
114 | |||
115 | for (i = 0; i < nr; i++) { | ||
116 | if (skt->stat[i].irq) | ||
117 | free_irq(skt->stat[i].irq, skt); | ||
118 | if (gpio_is_valid(skt->stat[i].gpio)) | ||
119 | gpio_free(skt->stat[i].gpio); | ||
120 | } | ||
121 | |||
122 | if (skt->ops->hw_shutdown) | ||
123 | skt->ops->hw_shutdown(skt); | ||
124 | } | ||
125 | |||
126 | static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
127 | { | ||
128 | __soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat)); | ||
129 | } | ||
130 | |||
131 | static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
132 | { | ||
133 | int ret = 0, i; | ||
134 | |||
135 | if (skt->ops->hw_init) { | ||
136 | ret = skt->ops->hw_init(skt); | ||
137 | if (ret) | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | for (i = 0; i < ARRAY_SIZE(skt->stat); i++) { | ||
142 | if (gpio_is_valid(skt->stat[i].gpio)) { | ||
143 | int irq; | ||
144 | |||
145 | ret = gpio_request_one(skt->stat[i].gpio, GPIOF_IN, | ||
146 | skt->stat[i].name); | ||
147 | if (ret) { | ||
148 | __soc_pcmcia_hw_shutdown(skt, i); | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | irq = gpio_to_irq(skt->stat[i].gpio); | ||
153 | |||
154 | if (i == SOC_STAT_RDY) | ||
155 | skt->socket.pci_irq = irq; | ||
156 | else | ||
157 | skt->stat[i].irq = irq; | ||
158 | } | ||
159 | |||
160 | if (skt->stat[i].irq) { | ||
161 | ret = request_irq(skt->stat[i].irq, | ||
162 | soc_common_pcmcia_interrupt, | ||
163 | IRQF_TRIGGER_NONE, | ||
164 | skt->stat[i].name, skt); | ||
165 | if (ret) { | ||
166 | if (gpio_is_valid(skt->stat[i].gpio)) | ||
167 | gpio_free(skt->stat[i].gpio); | ||
168 | __soc_pcmcia_hw_shutdown(skt, i); | ||
169 | return ret; | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | |||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | static void soc_pcmcia_hw_enable(struct soc_pcmcia_socket *skt) | ||
178 | { | ||
179 | int i; | ||
180 | |||
181 | for (i = 0; i < ARRAY_SIZE(skt->stat); i++) | ||
182 | if (skt->stat[i].irq) { | ||
183 | irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_RISING); | ||
184 | irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_BOTH); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt) | ||
189 | { | ||
190 | int i; | ||
191 | |||
192 | for (i = 0; i < ARRAY_SIZE(skt->stat); i++) | ||
193 | if (skt->stat[i].irq) | ||
194 | irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE); | ||
195 | } | ||
196 | |||
107 | static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) | 197 | static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) |
108 | { | 198 | { |
109 | struct pcmcia_state state; | 199 | struct pcmcia_state state; |
@@ -111,6 +201,22 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) | |||
111 | 201 | ||
112 | memset(&state, 0, sizeof(struct pcmcia_state)); | 202 | memset(&state, 0, sizeof(struct pcmcia_state)); |
113 | 203 | ||
204 | /* Make battery voltage state report 'good' */ | ||
205 | state.bvd1 = 1; | ||
206 | state.bvd2 = 1; | ||
207 | |||
208 | /* CD is active low by default */ | ||
209 | if (gpio_is_valid(skt->stat[SOC_STAT_CD].gpio)) | ||
210 | state.detect = !gpio_get_value(skt->stat[SOC_STAT_CD].gpio); | ||
211 | |||
212 | /* RDY and BVD are active high by default */ | ||
213 | if (gpio_is_valid(skt->stat[SOC_STAT_RDY].gpio)) | ||
214 | state.ready = !!gpio_get_value(skt->stat[SOC_STAT_RDY].gpio); | ||
215 | if (gpio_is_valid(skt->stat[SOC_STAT_BVD1].gpio)) | ||
216 | state.bvd1 = !!gpio_get_value(skt->stat[SOC_STAT_BVD1].gpio); | ||
217 | if (gpio_is_valid(skt->stat[SOC_STAT_BVD2].gpio)) | ||
218 | state.bvd2 = !!gpio_get_value(skt->stat[SOC_STAT_BVD2].gpio); | ||
219 | |||
114 | skt->ops->socket_state(skt, &state); | 220 | skt->ops->socket_state(skt, &state); |
115 | 221 | ||
116 | stat = state.detect ? SS_DETECT : 0; | 222 | stat = state.detect ? SS_DETECT : 0; |
@@ -188,6 +294,7 @@ static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock) | |||
188 | debug(skt, 2, "initializing socket\n"); | 294 | debug(skt, 2, "initializing socket\n"); |
189 | if (skt->ops->socket_init) | 295 | if (skt->ops->socket_init) |
190 | skt->ops->socket_init(skt); | 296 | skt->ops->socket_init(skt); |
297 | soc_pcmcia_hw_enable(skt); | ||
191 | return 0; | 298 | return 0; |
192 | } | 299 | } |
193 | 300 | ||
@@ -207,6 +314,7 @@ static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock) | |||
207 | 314 | ||
208 | debug(skt, 2, "suspending socket\n"); | 315 | debug(skt, 2, "suspending socket\n"); |
209 | 316 | ||
317 | soc_pcmcia_hw_disable(skt); | ||
210 | if (skt->ops->socket_suspend) | 318 | if (skt->ops->socket_suspend) |
211 | skt->ops->socket_suspend(skt); | 319 | skt->ops->socket_suspend(skt); |
212 | 320 | ||
@@ -526,69 +634,6 @@ static struct pccard_operations soc_common_pcmcia_operations = { | |||
526 | }; | 634 | }; |
527 | 635 | ||
528 | 636 | ||
529 | int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt, | ||
530 | struct pcmcia_irqs *irqs, int nr) | ||
531 | { | ||
532 | int i, res = 0; | ||
533 | |||
534 | for (i = 0; i < nr; i++) { | ||
535 | if (irqs[i].sock != skt->nr) | ||
536 | continue; | ||
537 | res = request_irq(irqs[i].irq, soc_common_pcmcia_interrupt, | ||
538 | IRQF_DISABLED, irqs[i].str, skt); | ||
539 | if (res) | ||
540 | break; | ||
541 | irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); | ||
542 | } | ||
543 | |||
544 | if (res) { | ||
545 | printk(KERN_ERR "PCMCIA: request for IRQ%d failed (%d)\n", | ||
546 | irqs[i].irq, res); | ||
547 | |||
548 | while (i--) | ||
549 | if (irqs[i].sock == skt->nr) | ||
550 | free_irq(irqs[i].irq, skt); | ||
551 | } | ||
552 | return res; | ||
553 | } | ||
554 | EXPORT_SYMBOL(soc_pcmcia_request_irqs); | ||
555 | |||
556 | void soc_pcmcia_free_irqs(struct soc_pcmcia_socket *skt, | ||
557 | struct pcmcia_irqs *irqs, int nr) | ||
558 | { | ||
559 | int i; | ||
560 | |||
561 | for (i = 0; i < nr; i++) | ||
562 | if (irqs[i].sock == skt->nr) | ||
563 | free_irq(irqs[i].irq, skt); | ||
564 | } | ||
565 | EXPORT_SYMBOL(soc_pcmcia_free_irqs); | ||
566 | |||
567 | void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt, | ||
568 | struct pcmcia_irqs *irqs, int nr) | ||
569 | { | ||
570 | int i; | ||
571 | |||
572 | for (i = 0; i < nr; i++) | ||
573 | if (irqs[i].sock == skt->nr) | ||
574 | irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); | ||
575 | } | ||
576 | EXPORT_SYMBOL(soc_pcmcia_disable_irqs); | ||
577 | |||
578 | void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, | ||
579 | struct pcmcia_irqs *irqs, int nr) | ||
580 | { | ||
581 | int i; | ||
582 | |||
583 | for (i = 0; i < nr; i++) | ||
584 | if (irqs[i].sock == skt->nr) { | ||
585 | irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_RISING); | ||
586 | irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_BOTH); | ||
587 | } | ||
588 | } | ||
589 | EXPORT_SYMBOL(soc_pcmcia_enable_irqs); | ||
590 | |||
591 | |||
592 | static LIST_HEAD(soc_pcmcia_sockets); | 637 | static LIST_HEAD(soc_pcmcia_sockets); |
593 | static DEFINE_MUTEX(soc_pcmcia_sockets_lock); | 638 | static DEFINE_MUTEX(soc_pcmcia_sockets_lock); |
594 | 639 | ||
@@ -635,6 +680,21 @@ module_exit(soc_pcmcia_cpufreq_unregister); | |||
635 | 680 | ||
636 | #endif | 681 | #endif |
637 | 682 | ||
683 | void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt, | ||
684 | struct pcmcia_low_level *ops, struct device *dev) | ||
685 | { | ||
686 | int i; | ||
687 | |||
688 | skt->ops = ops; | ||
689 | skt->socket.owner = ops->owner; | ||
690 | skt->socket.dev.parent = dev; | ||
691 | skt->socket.pci_irq = NO_IRQ; | ||
692 | |||
693 | for (i = 0; i < ARRAY_SIZE(skt->stat); i++) | ||
694 | skt->stat[i].gpio = -EINVAL; | ||
695 | } | ||
696 | EXPORT_SYMBOL(soc_pcmcia_init_one); | ||
697 | |||
638 | void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt) | 698 | void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt) |
639 | { | 699 | { |
640 | mutex_lock(&soc_pcmcia_sockets_lock); | 700 | mutex_lock(&soc_pcmcia_sockets_lock); |
@@ -642,8 +702,9 @@ void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt) | |||
642 | 702 | ||
643 | pcmcia_unregister_socket(&skt->socket); | 703 | pcmcia_unregister_socket(&skt->socket); |
644 | 704 | ||
645 | skt->ops->hw_shutdown(skt); | 705 | soc_pcmcia_hw_shutdown(skt); |
646 | 706 | ||
707 | /* should not be required; violates some lowlevel drivers */ | ||
647 | soc_common_pcmcia_config_skt(skt, &dead_socket); | 708 | soc_common_pcmcia_config_skt(skt, &dead_socket); |
648 | 709 | ||
649 | list_del(&skt->node); | 710 | list_del(&skt->node); |
@@ -700,7 +761,7 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) | |||
700 | */ | 761 | */ |
701 | skt->ops->set_timing(skt); | 762 | skt->ops->set_timing(skt); |
702 | 763 | ||
703 | ret = skt->ops->hw_init(skt); | 764 | ret = soc_pcmcia_hw_init(skt); |
704 | if (ret) | 765 | if (ret) |
705 | goto out_err_6; | 766 | goto out_err_6; |
706 | 767 | ||
@@ -733,7 +794,7 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) | |||
733 | pcmcia_unregister_socket(&skt->socket); | 794 | pcmcia_unregister_socket(&skt->socket); |
734 | 795 | ||
735 | out_err_7: | 796 | out_err_7: |
736 | skt->ops->hw_shutdown(skt); | 797 | soc_pcmcia_hw_shutdown(skt); |
737 | out_err_6: | 798 | out_err_6: |
738 | list_del(&skt->node); | 799 | list_del(&skt->node); |
739 | mutex_unlock(&soc_pcmcia_sockets_lock); | 800 | mutex_unlock(&soc_pcmcia_sockets_lock); |