Root/
1 | /* |
2 | * Viper/Zeus PCMCIA support |
3 | * Copyright 2004 Arcom Control Systems |
4 | * |
5 | * Maintained by Marc Zyngier <maz@misterjones.org> |
6 | * |
7 | * Based on: |
8 | * iPAQ h2200 PCMCIA support |
9 | * Copyright 2004 Koen Kooi <koen@vestingbar.nl> |
10 | * |
11 | * This file is subject to the terms and conditions of the GNU General Public |
12 | * License. See the file COPYING in the main directory of this archive for |
13 | * more details. |
14 | */ |
15 | |
16 | #include <linux/module.h> |
17 | #include <linux/init.h> |
18 | #include <linux/kernel.h> |
19 | #include <linux/errno.h> |
20 | #include <linux/interrupt.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/gpio.h> |
23 | |
24 | #include <pcmcia/ss.h> |
25 | |
26 | #include <asm/irq.h> |
27 | |
28 | #include <mach/arcom-pcmcia.h> |
29 | |
30 | #include "soc_common.h" |
31 | #include "pxa2xx_base.h" |
32 | |
33 | static struct platform_device *arcom_pcmcia_dev; |
34 | |
35 | static inline struct arcom_pcmcia_pdata *viper_get_pdata(void) |
36 | { |
37 | return arcom_pcmcia_dev->dev.platform_data; |
38 | } |
39 | |
40 | static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt) |
41 | { |
42 | struct arcom_pcmcia_pdata *pdata = viper_get_pdata(); |
43 | unsigned long flags; |
44 | |
45 | skt->stat[SOC_STAT_CD].gpio = pdata->cd_gpio; |
46 | skt->stat[SOC_STAT_CD].name = "PCMCIA_CD"; |
47 | skt->stat[SOC_STAT_RDY].gpio = pdata->rdy_gpio; |
48 | skt->stat[SOC_STAT_RDY].name = "CF ready"; |
49 | |
50 | if (gpio_request(pdata->pwr_gpio, "CF power")) |
51 | goto err_request_pwr; |
52 | |
53 | local_irq_save(flags); |
54 | |
55 | if (gpio_direction_output(pdata->pwr_gpio, 0)) { |
56 | local_irq_restore(flags); |
57 | goto err_dir; |
58 | } |
59 | |
60 | local_irq_restore(flags); |
61 | |
62 | return 0; |
63 | |
64 | err_dir: |
65 | gpio_free(pdata->pwr_gpio); |
66 | err_request_pwr: |
67 | dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs\n"); |
68 | return -1; |
69 | } |
70 | |
71 | /* |
72 | * Release all resources. |
73 | */ |
74 | static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) |
75 | { |
76 | struct arcom_pcmcia_pdata *pdata = viper_get_pdata(); |
77 | |
78 | gpio_free(pdata->pwr_gpio); |
79 | } |
80 | |
81 | static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt, |
82 | struct pcmcia_state *state) |
83 | { |
84 | state->vs_3v = 1; /* Can only apply 3.3V */ |
85 | state->vs_Xv = 0; |
86 | } |
87 | |
88 | static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, |
89 | const socket_state_t *state) |
90 | { |
91 | struct arcom_pcmcia_pdata *pdata = viper_get_pdata(); |
92 | |
93 | /* Silently ignore Vpp, output enable, speaker enable. */ |
94 | pdata->reset(state->flags & SS_RESET); |
95 | |
96 | /* Apply socket voltage */ |
97 | switch (state->Vcc) { |
98 | case 0: |
99 | gpio_set_value(pdata->pwr_gpio, 0); |
100 | break; |
101 | case 33: |
102 | gpio_set_value(pdata->pwr_gpio, 1); |
103 | break; |
104 | default: |
105 | dev_err(&arcom_pcmcia_dev->dev, "Unsupported Vcc:%d\n", state->Vcc); |
106 | return -1; |
107 | } |
108 | |
109 | return 0; |
110 | } |
111 | |
112 | static struct pcmcia_low_level viper_pcmcia_ops = { |
113 | .owner = THIS_MODULE, |
114 | .hw_init = viper_pcmcia_hw_init, |
115 | .hw_shutdown = viper_pcmcia_hw_shutdown, |
116 | .socket_state = viper_pcmcia_socket_state, |
117 | .configure_socket = viper_pcmcia_configure_socket, |
118 | .nr = 1, |
119 | }; |
120 | |
121 | static struct platform_device *viper_pcmcia_device; |
122 | |
123 | static int viper_pcmcia_probe(struct platform_device *pdev) |
124 | { |
125 | int ret; |
126 | |
127 | /* I can't imagine more than one device, but you never know... */ |
128 | if (arcom_pcmcia_dev) |
129 | return -EEXIST; |
130 | |
131 | if (!pdev->dev.platform_data) |
132 | return -EINVAL; |
133 | |
134 | viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); |
135 | if (!viper_pcmcia_device) |
136 | return -ENOMEM; |
137 | |
138 | arcom_pcmcia_dev = pdev; |
139 | |
140 | viper_pcmcia_device->dev.parent = &pdev->dev; |
141 | |
142 | ret = platform_device_add_data(viper_pcmcia_device, |
143 | &viper_pcmcia_ops, |
144 | sizeof(viper_pcmcia_ops)); |
145 | |
146 | if (!ret) |
147 | ret = platform_device_add(viper_pcmcia_device); |
148 | |
149 | if (ret) { |
150 | platform_device_put(viper_pcmcia_device); |
151 | arcom_pcmcia_dev = NULL; |
152 | } |
153 | |
154 | return ret; |
155 | } |
156 | |
157 | static int viper_pcmcia_remove(struct platform_device *pdev) |
158 | { |
159 | platform_device_unregister(viper_pcmcia_device); |
160 | arcom_pcmcia_dev = NULL; |
161 | return 0; |
162 | } |
163 | |
164 | static struct platform_device_id viper_pcmcia_id_table[] = { |
165 | { .name = "viper-pcmcia", }, |
166 | { .name = "zeus-pcmcia", }, |
167 | { }, |
168 | }; |
169 | |
170 | static struct platform_driver viper_pcmcia_driver = { |
171 | .probe = viper_pcmcia_probe, |
172 | .remove = viper_pcmcia_remove, |
173 | .driver = { |
174 | .name = "arcom-pcmcia", |
175 | .owner = THIS_MODULE, |
176 | }, |
177 | .id_table = viper_pcmcia_id_table, |
178 | }; |
179 | |
180 | module_platform_driver(viper_pcmcia_driver); |
181 | |
182 | MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table); |
183 | MODULE_LICENSE("GPL"); |
184 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9