Root/drivers/pcmcia/pxa2xx_palmtc.c

1/*
2 * linux/drivers/pcmcia/pxa2xx_palmtc.c
3 *
4 * Driver for Palm Tungsten|C PCMCIA
5 *
6 * Copyright (C) 2008 Alex Osborne <ato@meshy.org>
7 * Copyright (C) 2009 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#include <linux/gpio.h>
18#include <linux/delay.h>
19
20#include <asm/mach-types.h>
21#include <mach/palmtc.h>
22#include "soc_common.h"
23
24static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
25{
26    int ret;
27
28    ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_POWER1, "PCMCIA PWR1");
29    if (ret)
30        goto err1;
31    ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_POWER1, 0);
32    if (ret)
33        goto err2;
34
35    ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_POWER2, "PCMCIA PWR2");
36    if (ret)
37        goto err2;
38    ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_POWER2, 0);
39    if (ret)
40        goto err3;
41
42    ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_POWER3, "PCMCIA PWR3");
43    if (ret)
44        goto err3;
45    ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_POWER3, 0);
46    if (ret)
47        goto err4;
48
49    ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_RESET, "PCMCIA RST");
50    if (ret)
51        goto err4;
52    ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
53    if (ret)
54        goto err5;
55
56    ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_READY, "PCMCIA RDY");
57    if (ret)
58        goto err5;
59    ret = gpio_direction_input(GPIO_NR_PALMTC_PCMCIA_READY);
60    if (ret)
61        goto err6;
62
63    ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_PWRREADY, "PCMCIA PWRRDY");
64    if (ret)
65        goto err6;
66    ret = gpio_direction_input(GPIO_NR_PALMTC_PCMCIA_PWRREADY);
67    if (ret)
68        goto err7;
69
70    skt->socket.pci_irq = IRQ_GPIO(GPIO_NR_PALMTC_PCMCIA_READY);
71    return 0;
72
73err7:
74    gpio_free(GPIO_NR_PALMTC_PCMCIA_PWRREADY);
75err6:
76    gpio_free(GPIO_NR_PALMTC_PCMCIA_READY);
77err5:
78    gpio_free(GPIO_NR_PALMTC_PCMCIA_RESET);
79err4:
80    gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER3);
81err3:
82    gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER2);
83err2:
84    gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER1);
85err1:
86    return ret;
87}
88
89static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
90{
91    gpio_free(GPIO_NR_PALMTC_PCMCIA_PWRREADY);
92    gpio_free(GPIO_NR_PALMTC_PCMCIA_READY);
93    gpio_free(GPIO_NR_PALMTC_PCMCIA_RESET);
94    gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER3);
95    gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER2);
96    gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER1);
97}
98
99static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
100                    struct pcmcia_state *state)
101{
102    state->detect = 1; /* always inserted */
103    state->ready = !!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_READY);
104    state->bvd1 = 1;
105    state->bvd2 = 1;
106    state->wrprot = 0;
107    state->vs_3v = 1;
108    state->vs_Xv = 0;
109}
110
111static int palmtc_wifi_powerdown(void)
112{
113    gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
114    gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 0);
115    mdelay(40);
116    gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 0);
117    return 0;
118}
119
120static int palmtc_wifi_powerup(void)
121{
122    int timeout = 50;
123
124    gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 1);
125    mdelay(50);
126
127    /* Power up the card, 1.8V first, after a while 3.3V */
128    gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 1);
129    mdelay(100);
130    gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 1);
131
132    /* Wait till the card is ready */
133    while (!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_PWRREADY) &&
134        timeout) {
135        mdelay(1);
136        timeout--;
137    }
138
139    /* Power down the WiFi in case of error */
140    if (!timeout) {
141        palmtc_wifi_powerdown();
142        return 1;
143    }
144
145    /* Reset the card */
146    gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
147    mdelay(20);
148    gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 0);
149    mdelay(25);
150
151    gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 0);
152
153    return 0;
154}
155
156static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
157                    const socket_state_t *state)
158{
159    int ret = 1;
160
161    if (state->Vcc == 0)
162        ret = palmtc_wifi_powerdown();
163    else if (state->Vcc == 33)
164        ret = palmtc_wifi_powerup();
165
166    return ret;
167}
168
169static void palmtc_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
170{
171}
172
173static void palmtc_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
174{
175}
176
177static struct pcmcia_low_level palmtc_pcmcia_ops = {
178    .owner = THIS_MODULE,
179
180    .first = 0,
181    .nr = 1,
182
183    .hw_init = palmtc_pcmcia_hw_init,
184    .hw_shutdown = palmtc_pcmcia_hw_shutdown,
185
186    .socket_state = palmtc_pcmcia_socket_state,
187    .configure_socket = palmtc_pcmcia_configure_socket,
188
189    .socket_init = palmtc_pcmcia_socket_init,
190    .socket_suspend = palmtc_pcmcia_socket_suspend,
191};
192
193static struct platform_device *palmtc_pcmcia_device;
194
195static int __init palmtc_pcmcia_init(void)
196{
197    int ret;
198
199    if (!machine_is_palmtc())
200        return -ENODEV;
201
202    palmtc_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
203    if (!palmtc_pcmcia_device)
204        return -ENOMEM;
205
206    ret = platform_device_add_data(palmtc_pcmcia_device, &palmtc_pcmcia_ops,
207                    sizeof(palmtc_pcmcia_ops));
208
209    if (!ret)
210        ret = platform_device_add(palmtc_pcmcia_device);
211
212    if (ret)
213        platform_device_put(palmtc_pcmcia_device);
214
215    return ret;
216}
217
218static void __exit palmtc_pcmcia_exit(void)
219{
220    platform_device_unregister(palmtc_pcmcia_device);
221}
222
223module_init(palmtc_pcmcia_init);
224module_exit(palmtc_pcmcia_exit);
225
226MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
227        " Marek Vasut <marek.vasut@gmail.com>");
228MODULE_DESCRIPTION("PCMCIA support for Palm Tungsten|C");
229MODULE_ALIAS("platform:pxa2xx-pcmcia");
230MODULE_LICENSE("GPL");
231

Archive Download this file



interactive