aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia/pxa2xx_viper.c
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@altran.com>2008-08-19 06:15:53 -0400
committerMarc Zyngier <maz@young-lust.wild-wind.fr.eu.org>2008-09-09 11:41:53 -0400
commit20f18ff32fe311f60770ac70395b01c06758923b (patch)
tree4b1c11b306ce8b24d1b735aa4729405bd9818c2d /drivers/pcmcia/pxa2xx_viper.c
parent175ff20f6a681effa82d67e3656c4cc3e7117600 (diff)
Add support for the Arcom/Eurotech Viper SBC CompactFlash card slot
The Arcom/Eurotech Viper needs some extra care to run. On this board, the PC104 connector is actually wired to the second PCMCIA slot. Therefore, this second socket needs to be enabled, despite not being managed by the PCMCIA code. I'd rather have the MECR setup in the platform support code so I could, for example, use the PC104 bus without having the PCMCIA module loaded. Signed-off-by: Marc Zyngier <marc.zyngier@altran.com>
Diffstat (limited to 'drivers/pcmcia/pxa2xx_viper.c')
-rw-r--r--drivers/pcmcia/pxa2xx_viper.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/drivers/pcmcia/pxa2xx_viper.c b/drivers/pcmcia/pxa2xx_viper.c
new file mode 100644
index 000000000000..dd10481be7bf
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_viper.c
@@ -0,0 +1,179 @@
1/*
2 * VIPER PCMCIA support
3 * Copyright 2004 Arcom Control Systems
4 *
5 * Maintained by Marc Zyngier <maz@misterjones.org>
6 * <marc.zyngier@altran.com>
7 *
8 * Based on:
9 * iPAQ h2200 PCMCIA support
10 * Copyright 2004 Koen Kooi <koen@vestingbar.nl>
11 *
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file COPYING in the main directory of this archive for
14 * more details.
15 */
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/interrupt.h>
22#include <linux/platform_device.h>
23#include <linux/gpio.h>
24
25#include <pcmcia/ss.h>
26
27#include <asm/irq.h>
28
29#include <mach/pxa-regs.h>
30#include <mach/viper.h>
31#include <asm/mach-types.h>
32
33#include "soc_common.h"
34#include "pxa2xx_base.h"
35
36static struct pcmcia_irqs irqs[] = {
37 { 0, gpio_to_irq(VIPER_CF_CD_GPIO), "PCMCIA_CD" }
38};
39
40static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
41{
42 unsigned long flags;
43
44 skt->irq = gpio_to_irq(VIPER_CF_RDY_GPIO);
45
46 if (gpio_request(VIPER_CF_CD_GPIO, "CF detect"))
47 goto err_request_cd;
48
49 if (gpio_request(VIPER_CF_RDY_GPIO, "CF ready"))
50 goto err_request_rdy;
51
52 if (gpio_request(VIPER_CF_POWER_GPIO, "CF power"))
53 goto err_request_pwr;
54
55 local_irq_save(flags);
56
57 /* GPIO 82 is the CF power enable line. initially off */
58 if (gpio_direction_output(VIPER_CF_POWER_GPIO, 0) ||
59 gpio_direction_input(VIPER_CF_CD_GPIO) ||
60 gpio_direction_input(VIPER_CF_RDY_GPIO)) {
61 local_irq_restore(flags);
62 goto err_dir;
63 }
64
65 local_irq_restore(flags);
66
67 return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
68
69err_dir:
70 gpio_free(VIPER_CF_POWER_GPIO);
71err_request_pwr:
72 gpio_free(VIPER_CF_RDY_GPIO);
73err_request_rdy:
74 gpio_free(VIPER_CF_CD_GPIO);
75err_request_cd:
76 printk(KERN_ERR "viper: Failed to setup PCMCIA GPIOs\n");
77 return -1;
78}
79
80/*
81 * Release all resources.
82 */
83static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
84{
85 soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
86 gpio_free(VIPER_CF_POWER_GPIO);
87 gpio_free(VIPER_CF_RDY_GPIO);
88 gpio_free(VIPER_CF_CD_GPIO);
89}
90
91static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
92 struct pcmcia_state *state)
93{
94 state->detect = gpio_get_value(VIPER_CF_CD_GPIO) ? 0 : 1;
95 state->ready = gpio_get_value(VIPER_CF_RDY_GPIO) ? 1 : 0;
96 state->bvd1 = 1;
97 state->bvd2 = 1;
98 state->wrprot = 0;
99 state->vs_3v = 1; /* Can only apply 3.3V */
100 state->vs_Xv = 0;
101}
102
103static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
104 const socket_state_t *state)
105{
106 /* Silently ignore Vpp, output enable, speaker enable. */
107 viper_cf_rst(state->flags & SS_RESET);
108
109 /* Apply socket voltage */
110 switch (state->Vcc) {
111 case 0:
112 gpio_set_value(VIPER_CF_POWER_GPIO, 0);
113 break;
114 case 33:
115 gpio_set_value(VIPER_CF_POWER_GPIO, 1);
116 break;
117 default:
118 printk(KERN_ERR "%s: Unsupported Vcc:%d\n",
119 __func__, state->Vcc);
120 return -1;
121 }
122
123 return 0;
124}
125
126static void viper_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
127{
128}
129
130static void viper_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
131{
132}
133
134static struct pcmcia_low_level viper_pcmcia_ops __initdata = {
135 .owner = THIS_MODULE,
136 .hw_init = viper_pcmcia_hw_init,
137 .hw_shutdown = viper_pcmcia_hw_shutdown,
138 .socket_state = viper_pcmcia_socket_state,
139 .configure_socket = viper_pcmcia_configure_socket,
140 .socket_init = viper_pcmcia_socket_init,
141 .socket_suspend = viper_pcmcia_socket_suspend,
142 .nr = 1,
143};
144
145static struct platform_device *viper_pcmcia_device;
146
147static int __init viper_pcmcia_init(void)
148{
149 int ret;
150
151 if (!machine_is_viper())
152 return -ENODEV;
153
154 viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
155 if (!viper_pcmcia_device)
156 return -ENOMEM;
157
158 ret = platform_device_add_data(viper_pcmcia_device,
159 &viper_pcmcia_ops,
160 sizeof(viper_pcmcia_ops));
161
162 if (!ret)
163 ret = platform_device_add(viper_pcmcia_device);
164
165 if (ret)
166 platform_device_put(viper_pcmcia_device);
167
168 return ret;
169}
170
171static void __exit viper_pcmcia_exit(void)
172{
173 platform_device_unregister(viper_pcmcia_device);
174}
175
176module_init(viper_pcmcia_init);
177module_exit(viper_pcmcia_exit);
178
179MODULE_LICENSE("GPL");