aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pcmcia/Kconfig2
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/pxa2xx_base.c44
-rw-r--r--drivers/pcmcia/pxa2xx_viper.c179
4 files changed, 203 insertions, 23 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index e0f884034c9f..de57e7e17868 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -220,7 +220,7 @@ config PCMCIA_PXA2XX
220 tristate "PXA2xx support" 220 tristate "PXA2xx support"
221 depends on ARM && ARCH_PXA && PCMCIA 221 depends on ARM && ARCH_PXA && PCMCIA
222 depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ 222 depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
223 || MACH_ARMCORE || ARCH_PXA_PALM) 223 || MACH_ARMCORE || ARCH_PXA_PALM || ARCH_VIPER)
224 help 224 help
225 Say Y here to include support for the PXA2xx PCMCIA controller 225 Say Y here to include support for the PXA2xx PCMCIA controller
226 226
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 269a9e913ba2..76e859073cbb 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -72,5 +72,6 @@ pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock.o sa1111_generic.o
72pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o 72pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o
73pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o 73pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o
74pxa2xx_cs-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x270.o 74pxa2xx_cs-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x270.o
75pxa2xx_cs-$(CONFIG_ARCH_VIPER) += pxa2xx_viper.o
75pxa2xx_cs-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o 76pxa2xx_cs-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o
76 77
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 1b07af5a2ed3..13f1e0fd3f31 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -30,6 +30,7 @@
30#include <asm/system.h> 30#include <asm/system.h>
31#include <mach/pxa-regs.h> 31#include <mach/pxa-regs.h>
32#include <mach/pxa2xx-regs.h> 32#include <mach/pxa2xx-regs.h>
33#include <asm/mach-types.h>
33 34
34#include <pcmcia/cs_types.h> 35#include <pcmcia/cs_types.h>
35#include <pcmcia/ss.h> 36#include <pcmcia/ss.h>
@@ -166,18 +167,32 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
166} 167}
167#endif 168#endif
168 169
170static void pxa2xx_configure_sockets(struct device *dev)
171{
172 struct pcmcia_low_level *ops = dev->platform_data;
173
174 /*
175 * We have at least one socket, so set MECR:CIT
176 * (Card Is There)
177 */
178 MECR |= MECR_CIT;
179
180 /* Set MECR:NOS (Number Of Sockets) */
181 if (ops->nr > 1 || machine_is_viper())
182 MECR |= MECR_NOS;
183 else
184 MECR &= ~MECR_NOS;
185}
186
169int __pxa2xx_drv_pcmcia_probe(struct device *dev) 187int __pxa2xx_drv_pcmcia_probe(struct device *dev)
170{ 188{
171 int ret; 189 int ret;
172 struct pcmcia_low_level *ops; 190 struct pcmcia_low_level *ops;
173 int first, nr;
174 191
175 if (!dev || !dev->platform_data) 192 if (!dev || !dev->platform_data)
176 return -ENODEV; 193 return -ENODEV;
177 194
178 ops = (struct pcmcia_low_level *)dev->platform_data; 195 ops = (struct pcmcia_low_level *)dev->platform_data;
179 first = ops->first;
180 nr = ops->nr;
181 196
182 /* Provide our PXA2xx specific timing routines. */ 197 /* Provide our PXA2xx specific timing routines. */
183 ops->set_timing = pxa2xx_pcmcia_set_timing; 198 ops->set_timing = pxa2xx_pcmcia_set_timing;
@@ -185,21 +200,10 @@ int __pxa2xx_drv_pcmcia_probe(struct device *dev)
185 ops->frequency_change = pxa2xx_pcmcia_frequency_change; 200 ops->frequency_change = pxa2xx_pcmcia_frequency_change;
186#endif 201#endif
187 202
188 ret = soc_common_drv_pcmcia_probe(dev, ops, first, nr); 203 ret = soc_common_drv_pcmcia_probe(dev, ops, ops->first, ops->nr);
189 204
190 if (ret == 0) { 205 if (!ret)
191 /* 206 pxa2xx_configure_sockets(dev);
192 * We have at least one socket, so set MECR:CIT
193 * (Card Is There)
194 */
195 MECR |= MECR_CIT;
196
197 /* Set MECR:NOS (Number Of Sockets) */
198 if (nr > 1)
199 MECR |= MECR_NOS;
200 else
201 MECR &= ~MECR_NOS;
202 }
203 207
204 return ret; 208 return ret;
205} 209}
@@ -223,11 +227,7 @@ static int pxa2xx_drv_pcmcia_suspend(struct platform_device *dev, pm_message_t s
223 227
224static int pxa2xx_drv_pcmcia_resume(struct platform_device *dev) 228static int pxa2xx_drv_pcmcia_resume(struct platform_device *dev)
225{ 229{
226 struct pcmcia_low_level *ops = dev->dev.platform_data; 230 pxa2xx_configure_sockets(&dev->dev);
227 int nr = ops ? ops->nr : 0;
228
229 MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0);
230
231 return pcmcia_socket_dev_resume(&dev->dev); 231 return pcmcia_socket_dev_resume(&dev->dev);
232} 232}
233 233
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");