d06f6ff82614cdff67f8ab35b6651408beabf64c
[linux-2.6.git] / arch / arm / mach-tegra / board-enterprise-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-enterprise-sdhci.c
3  *
4  * Copyright (C) 2011-2012 NVIDIA Corporation.
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 #include <mach/io_dpd.h>
31
32 #include "gpio-names.h"
33 #include "board.h"
34
35
36 #define ENTERPRISE_WLAN_PWR     TEGRA_GPIO_PV2
37 #define ENTERPRISE_WLAN_RST     TEGRA_GPIO_PV3
38 #define ENTERPRISE_WLAN_WOW     TEGRA_GPIO_PU6
39 #define ENTERPRISE_SD_CD TEGRA_GPIO_PI5
40
41 static void (*wifi_status_cb)(int card_present, void *dev_id);
42 static void *wifi_status_cb_devid;
43 static int enterprise_wifi_status_register(void (*callback)(int , void *), void *);
44
45 static int enterprise_wifi_reset(int on);
46 static int enterprise_wifi_power(int on);
47 static int enterprise_wifi_set_carddetect(int val);
48
49 static struct wifi_platform_data enterprise_wifi_control = {
50         .set_power      = enterprise_wifi_power,
51         .set_reset      = enterprise_wifi_reset,
52         .set_carddetect = enterprise_wifi_set_carddetect,
53 };
54
55 static struct resource wifi_resource[] = {
56         [0] = {
57                 .name   = "bcm4329_wlan_irq",
58                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE,
59         },
60 };
61
62 static struct platform_device enterprise_wifi_device = {
63         .name           = "bcm4329_wlan",
64         .id             = 1,
65         .num_resources  = 1,
66         .resource       = wifi_resource,
67         .dev            = {
68                 .platform_data = &enterprise_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 #ifdef CONFIG_MMC_EMBEDDED_SDIO
112 static struct embedded_sdio_data embedded_sdio_data0 = {
113         .cccr   = {
114                 .sdio_vsn       = 2,
115                 .multi_block    = 1,
116                 .low_speed      = 0,
117                 .wide_bus       = 0,
118                 .high_power     = 1,
119                 .high_speed     = 1,
120         },
121         .cis  = {
122                 .vendor         = 0x02d0,
123                 .device         = 0x4329,
124         },
125 };
126 #endif
127
128 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
129         .mmc_data = {
130                 .register_status_notify = enterprise_wifi_status_register,
131 #ifdef CONFIG_MMC_EMBEDDED_SDIO
132                 .embedded_sdio = &embedded_sdio_data0,
133 #endif
134                 /* FIXME need to revert the built_in change
135                 once we use get the signal strength fix of
136                 bcmdhd driver from broadcom for bcm4329 chipset*/
137                 .built_in = 0,
138         },
139 #ifndef CONFIG_MMC_EMBEDDED_SDIO
140         .pm_flags = MMC_PM_KEEP_POWER,
141 #endif
142         .cd_gpio = -1,
143         .wp_gpio = -1,
144         .power_gpio = -1,
145         .tap_delay = 0x0F,
146         .max_clk_limit = 45000000,
147         .ddr_clk_limit = 41000000,
148 };
149
150 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
151         .cd_gpio = -1,
152         .wp_gpio = -1,
153         .power_gpio = -1,
154         .tap_delay = 0x0F,
155         .ddr_clk_limit = 41000000,
156 };
157
158 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
159         .cd_gpio = -1,
160         .wp_gpio = -1,
161         .power_gpio = -1,
162         .is_8bit = 1,
163         .tap_delay = 0x0F,
164         .ddr_clk_limit = 41000000,
165         .mmc_data = {
166                 .built_in = 1,
167         }
168 };
169
170 static struct platform_device tegra_sdhci_device0 = {
171         .name           = "sdhci-tegra",
172         .id             = 0,
173         .resource       = sdhci_resource0,
174         .num_resources  = ARRAY_SIZE(sdhci_resource0),
175         .dev = {
176                 .platform_data = &tegra_sdhci_platform_data0,
177         },
178 };
179
180 static struct platform_device tegra_sdhci_device2 = {
181         .name           = "sdhci-tegra",
182         .id             = 2,
183         .resource       = sdhci_resource2,
184         .num_resources  = ARRAY_SIZE(sdhci_resource2),
185         .dev = {
186                 .platform_data = &tegra_sdhci_platform_data2,
187         },
188 };
189
190 static struct platform_device tegra_sdhci_device3 = {
191         .name           = "sdhci-tegra",
192         .id             = 3,
193         .resource       = sdhci_resource3,
194         .num_resources  = ARRAY_SIZE(sdhci_resource3),
195         .dev = {
196                 .platform_data = &tegra_sdhci_platform_data3,
197         },
198 };
199
200 static int enterprise_wifi_status_register(
201                 void (*callback)(int card_present, void *dev_id),
202                 void *dev_id)
203 {
204         if (wifi_status_cb)
205                 return -EAGAIN;
206         wifi_status_cb = callback;
207         wifi_status_cb_devid = dev_id;
208         return 0;
209 }
210
211 static int enterprise_wifi_set_carddetect(int val)
212 {
213         pr_debug("%s: %d\n", __func__, val);
214         if (wifi_status_cb)
215                 wifi_status_cb(val, wifi_status_cb_devid);
216         else
217                 pr_warning("%s: Nobody to notify\n", __func__);
218         return 0;
219 }
220
221 static int enterprise_wifi_power(int on)
222 {
223         struct tegra_io_dpd *sd_dpd;
224
225         pr_debug("%s: %d\n", __func__, on);
226
227         /*
228          * FIXME : we need to revisit IO DPD code
229          * on how should multiple pins under DPD get controlled
230          *
231          * enterprise GPIO WLAN enable is part of SDMMC1 pin group
232          */
233         sd_dpd = tegra_io_dpd_get(&tegra_sdhci_device0.dev);
234         if (sd_dpd) {
235                 mutex_lock(&sd_dpd->delay_lock);
236                 tegra_io_dpd_disable(sd_dpd);
237                 mutex_unlock(&sd_dpd->delay_lock);
238         }
239         gpio_set_value(ENTERPRISE_WLAN_PWR, on);
240         mdelay(100);
241         gpio_set_value(ENTERPRISE_WLAN_RST, on);
242         mdelay(200);
243         if (sd_dpd) {
244                 mutex_lock(&sd_dpd->delay_lock);
245                 tegra_io_dpd_enable(sd_dpd);
246                 mutex_unlock(&sd_dpd->delay_lock);
247         }
248
249         return 0;
250 }
251
252 static int enterprise_wifi_reset(int on)
253 {
254         pr_debug("%s: do nothing\n", __func__);
255         return 0;
256 }
257
258 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
259 static int __init enterprise_wifi_prepower(void)
260 {
261         if (!machine_is_tegra_enterprise())
262                 return 0;
263
264         enterprise_wifi_power(1);
265
266         return 0;
267 }
268
269 subsys_initcall_sync(enterprise_wifi_prepower);
270 #endif
271
272 static int __init enterprise_wifi_init(void)
273 {
274         int rc;
275
276         rc = gpio_request(ENTERPRISE_WLAN_PWR, "wlan_power");
277         if (rc)
278                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
279         rc = gpio_request(ENTERPRISE_WLAN_RST, "wlan_rst");
280         if (rc)
281                 pr_err("WLAN_RST gpio request failed:%d\n", rc);
282         rc = gpio_request(ENTERPRISE_WLAN_WOW, "bcmsdh_sdmmc");
283         if (rc)
284                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
285
286         rc = gpio_direction_output(ENTERPRISE_WLAN_PWR, 0);
287         if (rc)
288                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
289         gpio_direction_output(ENTERPRISE_WLAN_RST, 0);
290         if (rc)
291                 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
292         rc = gpio_direction_input(ENTERPRISE_WLAN_WOW);
293         if (rc)
294                 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
295
296         wifi_resource[0].start = wifi_resource[0].end =
297                 gpio_to_irq(TEGRA_GPIO_PU6);
298         platform_device_register(&enterprise_wifi_device);
299         return 0;
300 }
301
302 int __init enterprise_sdhci_init(void)
303 {
304         platform_device_register(&tegra_sdhci_device3);
305
306         tegra_sdhci_platform_data2.cd_gpio = ENTERPRISE_SD_CD;
307         platform_device_register(&tegra_sdhci_device2);
308
309         platform_device_register(&tegra_sdhci_device0);
310         enterprise_wifi_init();
311         return 0;
312 }