• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/pcmcia/
1/*
2 * linux/drivers/pcmcia/pxa2xx_vpac270.c
3 *
4 * Driver for Voipac PXA270 PCMCIA and CF sockets
5 *
6 * Copyright (C) 2010
7 * Marek Vasut <marek.vasut@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/platform_device.h>
17
18#include <asm/mach-types.h>
19
20#include <mach/gpio.h>
21#include <mach/vpac270.h>
22
23#include "soc_common.h"
24
25static struct pcmcia_irqs cd_irqs[] = {
26	{
27		.sock = 0,
28		.irq  = IRQ_GPIO(GPIO84_VPAC270_PCMCIA_CD),
29		.str  = "PCMCIA CD"
30	},
31	{
32		.sock = 1,
33		.irq  = IRQ_GPIO(GPIO17_VPAC270_CF_CD),
34		.str  = "CF CD"
35	},
36};
37
38static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
39{
40	int ret;
41
42	if (skt->nr == 0) {
43		ret = gpio_request(GPIO84_VPAC270_PCMCIA_CD, "PCMCIA CD");
44		if (ret)
45			goto err1;
46		ret = gpio_direction_input(GPIO84_VPAC270_PCMCIA_CD);
47		if (ret)
48			goto err2;
49
50		ret = gpio_request(GPIO35_VPAC270_PCMCIA_RDY, "PCMCIA RDY");
51		if (ret)
52			goto err2;
53		ret = gpio_direction_input(GPIO35_VPAC270_PCMCIA_RDY);
54		if (ret)
55			goto err3;
56
57		ret = gpio_request(GPIO107_VPAC270_PCMCIA_PPEN, "PCMCIA PPEN");
58		if (ret)
59			goto err3;
60		ret = gpio_direction_output(GPIO107_VPAC270_PCMCIA_PPEN, 0);
61		if (ret)
62			goto err4;
63
64		ret = gpio_request(GPIO11_VPAC270_PCMCIA_RESET, "PCMCIA RESET");
65		if (ret)
66			goto err4;
67		ret = gpio_direction_output(GPIO11_VPAC270_PCMCIA_RESET, 0);
68		if (ret)
69			goto err5;
70
71		skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY);
72
73		return soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1);
74
75err5:
76		gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
77err4:
78		gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
79err3:
80		gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
81err2:
82		gpio_free(GPIO84_VPAC270_PCMCIA_CD);
83err1:
84		return ret;
85
86	} else {
87		ret = gpio_request(GPIO17_VPAC270_CF_CD, "CF CD");
88		if (ret)
89			goto err6;
90		ret = gpio_direction_input(GPIO17_VPAC270_CF_CD);
91		if (ret)
92			goto err7;
93
94		ret = gpio_request(GPIO12_VPAC270_CF_RDY, "CF RDY");
95		if (ret)
96			goto err7;
97		ret = gpio_direction_input(GPIO12_VPAC270_CF_RDY);
98		if (ret)
99			goto err8;
100
101		ret = gpio_request(GPIO16_VPAC270_CF_RESET, "CF RESET");
102		if (ret)
103			goto err8;
104		ret = gpio_direction_output(GPIO16_VPAC270_CF_RESET, 0);
105		if (ret)
106			goto err9;
107
108		skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY);
109
110		return soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1);
111
112err9:
113		gpio_free(GPIO16_VPAC270_CF_RESET);
114err8:
115		gpio_free(GPIO12_VPAC270_CF_RDY);
116err7:
117		gpio_free(GPIO17_VPAC270_CF_CD);
118err6:
119		return ret;
120
121	}
122}
123
124static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
125{
126	gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
127	gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
128	gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
129	gpio_free(GPIO84_VPAC270_PCMCIA_CD);
130	gpio_free(GPIO16_VPAC270_CF_RESET);
131	gpio_free(GPIO12_VPAC270_CF_RDY);
132	gpio_free(GPIO17_VPAC270_CF_CD);
133}
134
135static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
136					struct pcmcia_state *state)
137{
138	if (skt->nr == 0) {
139		state->detect = !gpio_get_value(GPIO84_VPAC270_PCMCIA_CD);
140		state->ready  = !!gpio_get_value(GPIO35_VPAC270_PCMCIA_RDY);
141	} else {
142		state->detect = !gpio_get_value(GPIO17_VPAC270_CF_CD);
143		state->ready  = !!gpio_get_value(GPIO12_VPAC270_CF_RDY);
144	}
145	state->bvd1   = 1;
146	state->bvd2   = 1;
147	state->wrprot = 0;
148	state->vs_3v  = 1;
149	state->vs_Xv  = 0;
150}
151
152static int
153vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
154				const socket_state_t *state)
155{
156	if (skt->nr == 0) {
157		gpio_set_value(GPIO11_VPAC270_PCMCIA_RESET,
158			(state->flags & SS_RESET));
159		gpio_set_value(GPIO107_VPAC270_PCMCIA_PPEN,
160			!(state->Vcc == 33 || state->Vcc == 50));
161	} else {
162		gpio_set_value(GPIO16_VPAC270_CF_RESET,
163			(state->flags & SS_RESET));
164	}
165
166	return 0;
167}
168
169static void vpac270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
170{
171}
172
173static void vpac270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
174{
175}
176
177static struct pcmcia_low_level vpac270_pcmcia_ops = {
178	.owner			= THIS_MODULE,
179
180	.first			= 0,
181	.nr			= 2,
182
183	.hw_init		= vpac270_pcmcia_hw_init,
184	.hw_shutdown		= vpac270_pcmcia_hw_shutdown,
185
186	.socket_state		= vpac270_pcmcia_socket_state,
187	.configure_socket	= vpac270_pcmcia_configure_socket,
188
189	.socket_init		= vpac270_pcmcia_socket_init,
190	.socket_suspend		= vpac270_pcmcia_socket_suspend,
191};
192
193static struct platform_device *vpac270_pcmcia_device;
194
195static int __init vpac270_pcmcia_init(void)
196{
197	int ret;
198
199	if (!machine_is_vpac270())
200		return -ENODEV;
201
202	vpac270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
203	if (!vpac270_pcmcia_device)
204		return -ENOMEM;
205
206	ret = platform_device_add_data(vpac270_pcmcia_device,
207		&vpac270_pcmcia_ops, sizeof(vpac270_pcmcia_ops));
208
209	if (!ret)
210		ret = platform_device_add(vpac270_pcmcia_device);
211
212	if (ret)
213		platform_device_put(vpac270_pcmcia_device);
214
215	return ret;
216}
217
218static void __exit vpac270_pcmcia_exit(void)
219{
220	platform_device_unregister(vpac270_pcmcia_device);
221}
222
223module_init(vpac270_pcmcia_init);
224module_exit(vpac270_pcmcia_exit);
225
226MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
227MODULE_DESCRIPTION("PCMCIA support for Voipac PXA270");
228MODULE_ALIAS("platform:pxa2xx-pcmcia");
229MODULE_LICENSE("GPL");
230