8a99d9252fc508269b4c5ba22d9f9889cf54f6c5
[linux-2.6.git] / arch / arm / mach-tegra / board-ventana-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-harmony-sdhci.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/resource.h>
18 #include <linux/platform_device.h>
19 #include <linux/wlan_plat.h>
20 #include <linux/delay.h>
21 #include <linux/gpio.h>
22 #include <linux/clk.h>
23 #include <linux/err.h>
24 #include <linux/mmc/host.h>
25
26 #include <asm/mach-types.h>
27 #include <mach/irqs.h>
28 #include <mach/iomap.h>
29 #include <mach/sdhci.h>
30
31 #include "gpio-names.h"
32 #include "board.h"
33
34 #define VENTANA_WLAN_PWR        TEGRA_GPIO_PK5
35 #define VENTANA_WLAN_RST        TEGRA_GPIO_PK6
36 #define VENTANA_WLAN_WOW        TEGRA_GPIO_PS0
37
38 static void (*wifi_status_cb)(int card_present, void *dev_id);
39 static void *wifi_status_cb_devid;
40 static int ventana_wifi_status_register(void (*callback)(int , void *), void *);
41 static struct clk *wifi_32k_clk;
42
43 static int ventana_wifi_reset(int on);
44 static int ventana_wifi_power(int on);
45 static int ventana_wifi_set_carddetect(int val);
46
47 static struct wifi_platform_data ventana_wifi_control = {
48         .set_power      = ventana_wifi_power,
49         .set_reset      = ventana_wifi_reset,
50         .set_carddetect = ventana_wifi_set_carddetect,
51 };
52
53 static struct resource wifi_resource[] = {
54         [0] = {
55                 .name  = "bcm4329_wlan_irq",
56                 .start = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0),
57                 .end   = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0),
58                 .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE,
59         },
60 };
61
62 static struct platform_device ventana_wifi_device = {
63         .name           = "bcm4329_wlan",
64         .id             = 1,
65         .num_resources  = 1,
66         .resource       = wifi_resource,
67         .dev            = {
68                 .platform_data = &ventana_wifi_control,
69         },
70 };
71
72 static struct resource sdhci_resource0[] = {
73         [0] = {
74                 .start  = INT_SDMMC1,
75                 .end    = INT_SDMMC1,
76                 .flags  = IORESOURCE_IRQ,
77         },
78         [1] = {
79                 .start  = TEGRA_SDMMC1_BASE,
80                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
81                 .flags  = IORESOURCE_MEM,
82         },
83 };
84
85 static struct resource sdhci_resource2[] = {
86         [0] = {
87                 .start  = INT_SDMMC3,
88                 .end    = INT_SDMMC3,
89                 .flags  = IORESOURCE_IRQ,
90         },
91         [1] = {
92                 .start  = TEGRA_SDMMC3_BASE,
93                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
94                 .flags  = IORESOURCE_MEM,
95         },
96 };
97
98 static struct resource sdhci_resource3[] = {
99         [0] = {
100                 .start  = INT_SDMMC4,
101                 .end    = INT_SDMMC4,
102                 .flags  = IORESOURCE_IRQ,
103         },
104         [1] = {
105                 .start  = TEGRA_SDMMC4_BASE,
106                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
107                 .flags  = IORESOURCE_MEM,
108         },
109 };
110
111 static struct embedded_sdio_data embedded_sdio_data0 = {
112         .cccr   = {
113                 .sdio_vsn       = 2,
114                 .multi_block    = 1,
115                 .low_speed      = 0,
116                 .wide_bus       = 0,
117                 .high_power     = 1,
118                 .high_speed     = 1,
119         },
120         .cis  = {
121                 .vendor         = 0x02d0,
122                 .device         = 0x4329,
123         },
124 };
125
126 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
127         .mmc_data = {
128                 .register_status_notify = ventana_wifi_status_register,
129                 .embedded_sdio = &embedded_sdio_data0,
130                 .built_in = 1,
131         },
132         .cd_gpio = -1,
133         .wp_gpio = -1,
134         .power_gpio = -1,
135 };
136
137 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
138         .cd_gpio = TEGRA_GPIO_PI5,
139         .wp_gpio = TEGRA_GPIO_PH1,
140         .power_gpio = TEGRA_GPIO_PT3,
141 };
142
143 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
144         .is_8bit = 1,
145         .cd_gpio = -1,
146         .wp_gpio = -1,
147         .power_gpio = TEGRA_GPIO_PI6,
148         .mmc_data = {
149                 .built_in = 1,
150         }
151 };
152
153 static struct platform_device tegra_sdhci_device0 = {
154         .name           = "sdhci-tegra",
155         .id             = 0,
156         .resource       = sdhci_resource0,
157         .num_resources  = ARRAY_SIZE(sdhci_resource0),
158         .dev = {
159                 .platform_data = &tegra_sdhci_platform_data0,
160         },
161 };
162
163 static struct platform_device tegra_sdhci_device2 = {
164         .name           = "sdhci-tegra",
165         .id             = 2,
166         .resource       = sdhci_resource2,
167         .num_resources  = ARRAY_SIZE(sdhci_resource2),
168         .dev = {
169                 .platform_data = &tegra_sdhci_platform_data2,
170         },
171 };
172
173 static struct platform_device tegra_sdhci_device3 = {
174         .name           = "sdhci-tegra",
175         .id             = 3,
176         .resource       = sdhci_resource3,
177         .num_resources  = ARRAY_SIZE(sdhci_resource3),
178         .dev = {
179                 .platform_data = &tegra_sdhci_platform_data3,
180         },
181 };
182
183 static int ventana_wifi_status_register(
184                 void (*callback)(int card_present, void *dev_id),
185                 void *dev_id)
186 {
187         if (wifi_status_cb)
188                 return -EAGAIN;
189         wifi_status_cb = callback;
190         wifi_status_cb_devid = dev_id;
191         return 0;
192 }
193
194 static int ventana_wifi_set_carddetect(int val)
195 {
196         pr_debug("%s: %d\n", __func__, val);
197         if (wifi_status_cb)
198                 wifi_status_cb(val, wifi_status_cb_devid);
199         else
200                 pr_warning("%s: Nobody to notify\n", __func__);
201         return 0;
202 }
203
204 static int ventana_wifi_power(int on)
205 {
206         pr_debug("%s: %d\n", __func__, on);
207
208         gpio_set_value(VENTANA_WLAN_PWR, on);
209         mdelay(100);
210         gpio_set_value(VENTANA_WLAN_RST, on);
211         mdelay(200);
212
213         if (on)
214                 clk_enable(wifi_32k_clk);
215         else
216                 clk_disable(wifi_32k_clk);
217
218         return 0;
219 }
220
221 static int ventana_wifi_reset(int on)
222 {
223         pr_debug("%s: do nothing\n", __func__);
224         return 0;
225 }
226
227 static int __init ventana_wifi_init(void)
228 {
229         wifi_32k_clk = clk_get_sys(NULL, "blink");
230         if (IS_ERR(wifi_32k_clk)) {
231                 pr_err("%s: unable to get blink clock\n", __func__);
232                 return PTR_ERR(wifi_32k_clk);
233         }
234
235         gpio_request(VENTANA_WLAN_PWR, "wlan_power");
236         gpio_request(VENTANA_WLAN_RST, "wlan_rst");
237         gpio_request(VENTANA_WLAN_WOW, "bcmsdh_sdmmc");
238
239         tegra_gpio_enable(VENTANA_WLAN_PWR);
240         tegra_gpio_enable(VENTANA_WLAN_RST);
241         tegra_gpio_enable(VENTANA_WLAN_WOW);
242
243         gpio_direction_output(VENTANA_WLAN_PWR, 0);
244         gpio_direction_output(VENTANA_WLAN_RST, 0);
245         gpio_direction_input(VENTANA_WLAN_WOW);
246
247         platform_device_register(&ventana_wifi_device);
248
249         device_init_wakeup(&ventana_wifi_device.dev, 1);
250         device_set_wakeup_enable(&ventana_wifi_device.dev, 0);
251
252         return 0;
253 }
254 int __init ventana_sdhci_init(void)
255 {
256         tegra_gpio_enable(tegra_sdhci_platform_data2.power_gpio);
257         tegra_gpio_enable(tegra_sdhci_platform_data2.cd_gpio);
258         tegra_gpio_enable(tegra_sdhci_platform_data2.wp_gpio);
259         tegra_gpio_enable(tegra_sdhci_platform_data3.power_gpio);
260
261         platform_device_register(&tegra_sdhci_device3);
262         platform_device_register(&tegra_sdhci_device2);
263         platform_device_register(&tegra_sdhci_device0);
264
265         ventana_wifi_init();
266         return 0;
267 }