blob: b32d05f86789202c1171981778dfca214e0e4ffa [file] [log] [blame]
Marek Vasut36d618b2009-07-16 13:30:47 +02001/*
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>
Marek Vasut9ed3fbf2011-01-15 19:22:19 +01007 * Copyright (C) 2009-2011 Marek Vasut <marek.vasut@gmail.com>
Marek Vasut36d618b2009-07-16 13:30:47 +02008 *
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
Marek Vasutba388302011-01-15 18:59:43 +010024static struct gpio palmtc_pcmcia_gpios[] = {
25 { GPIO_NR_PALMTC_PCMCIA_POWER1, GPIOF_INIT_LOW, "PCMCIA Power 1" },
26 { GPIO_NR_PALMTC_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" },
27 { GPIO_NR_PALMTC_PCMCIA_POWER3, GPIOF_INIT_LOW, "PCMCIA Power 3" },
28 { GPIO_NR_PALMTC_PCMCIA_RESET, GPIOF_INIT_HIGH,"PCMCIA Reset" },
Marek Vasutba388302011-01-15 18:59:43 +010029 { GPIO_NR_PALMTC_PCMCIA_PWRREADY, GPIOF_IN, "PCMCIA Power Ready" },
30};
31
Marek Vasut36d618b2009-07-16 13:30:47 +020032static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
33{
34 int ret;
35
Marek Vasutba388302011-01-15 18:59:43 +010036 ret = gpio_request_array(palmtc_pcmcia_gpios,
37 ARRAY_SIZE(palmtc_pcmcia_gpios));
Marek Vasut36d618b2009-07-16 13:30:47 +020038
Russell Kinga9bb5a42012-01-13 22:56:32 +000039 skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTC_PCMCIA_READY;
40 skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
Marek Vasut36d618b2009-07-16 13:30:47 +020041
Marek Vasut36d618b2009-07-16 13:30:47 +020042 return ret;
43}
44
45static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
46{
Marek Vasutba388302011-01-15 18:59:43 +010047 gpio_free_array(palmtc_pcmcia_gpios, ARRAY_SIZE(palmtc_pcmcia_gpios));
Marek Vasut36d618b2009-07-16 13:30:47 +020048}
49
50static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
51 struct pcmcia_state *state)
52{
53 state->detect = 1; /* always inserted */
Marek Vasut36d618b2009-07-16 13:30:47 +020054 state->wrprot = 0;
55 state->vs_3v = 1;
56 state->vs_Xv = 0;
57}
58
59static int palmtc_wifi_powerdown(void)
60{
61 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
62 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 0);
63 mdelay(40);
64 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 0);
65 return 0;
66}
67
68static int palmtc_wifi_powerup(void)
69{
70 int timeout = 50;
71
72 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 1);
73 mdelay(50);
74
75 /* Power up the card, 1.8V first, after a while 3.3V */
76 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 1);
77 mdelay(100);
78 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 1);
79
80 /* Wait till the card is ready */
81 while (!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_PWRREADY) &&
82 timeout) {
83 mdelay(1);
84 timeout--;
85 }
86
87 /* Power down the WiFi in case of error */
88 if (!timeout) {
89 palmtc_wifi_powerdown();
90 return 1;
91 }
92
93 /* Reset the card */
94 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
95 mdelay(20);
96 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 0);
97 mdelay(25);
98
99 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 0);
100
101 return 0;
102}
103
104static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
105 const socket_state_t *state)
106{
Marek Vasut6cf44422009-09-03 04:40:03 +0200107 int ret = 1;
Marek Vasut36d618b2009-07-16 13:30:47 +0200108
109 if (state->Vcc == 0)
110 ret = palmtc_wifi_powerdown();
111 else if (state->Vcc == 33)
112 ret = palmtc_wifi_powerup();
113
114 return ret;
115}
116
Marek Vasut36d618b2009-07-16 13:30:47 +0200117static struct pcmcia_low_level palmtc_pcmcia_ops = {
118 .owner = THIS_MODULE,
119
120 .first = 0,
121 .nr = 1,
122
123 .hw_init = palmtc_pcmcia_hw_init,
124 .hw_shutdown = palmtc_pcmcia_hw_shutdown,
125
126 .socket_state = palmtc_pcmcia_socket_state,
127 .configure_socket = palmtc_pcmcia_configure_socket,
Marek Vasut36d618b2009-07-16 13:30:47 +0200128};
129
130static struct platform_device *palmtc_pcmcia_device;
131
132static int __init palmtc_pcmcia_init(void)
133{
134 int ret;
135
136 if (!machine_is_palmtc())
137 return -ENODEV;
138
139 palmtc_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
140 if (!palmtc_pcmcia_device)
141 return -ENOMEM;
142
143 ret = platform_device_add_data(palmtc_pcmcia_device, &palmtc_pcmcia_ops,
144 sizeof(palmtc_pcmcia_ops));
145
146 if (!ret)
147 ret = platform_device_add(palmtc_pcmcia_device);
148
149 if (ret)
150 platform_device_put(palmtc_pcmcia_device);
151
152 return ret;
153}
154
155static void __exit palmtc_pcmcia_exit(void)
156{
157 platform_device_unregister(palmtc_pcmcia_device);
158}
159
160module_init(palmtc_pcmcia_init);
161module_exit(palmtc_pcmcia_exit);
162
163MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
164 " Marek Vasut <marek.vasut@gmail.com>");
165MODULE_DESCRIPTION("PCMCIA support for Palm Tungsten|C");
166MODULE_ALIAS("platform:pxa2xx-pcmcia");
167MODULE_LICENSE("GPL");