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