Merge commit 'main-jb-2012.08.03-B4' into t114-0806
[linux-2.6.git] / arch / arm / mach-tegra / board-cardhu-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-harmony-sdhci.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  * Copyright (C) 2011-2012 NVIDIA Corporation.
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 #include <linux/resource.h>
19 #include <linux/platform_device.h>
20 #include <linux/wlan_plat.h>
21 #include <linux/delay.h>
22 #include <linux/gpio.h>
23 #include <linux/clk.h>
24 #include <linux/err.h>
25 #include <linux/mmc/host.h>
26
27 #include <asm/mach-types.h>
28 #include <mach/irqs.h>
29 #include <mach/iomap.h>
30 #include <mach/sdhci.h>
31 #include <mach/io_dpd.h>
32
33 #include "gpio-names.h"
34 #include "board.h"
35 #include "board-cardhu.h"
36
37 #define CARDHU_WLAN_PWR TEGRA_GPIO_PD4
38 #define CARDHU_WLAN_RST TEGRA_GPIO_PD3
39 #define CARDHU_WLAN_WOW TEGRA_GPIO_PO4
40 #define CARDHU_SD_CD TEGRA_GPIO_PI5
41 #define CARDHU_SD_WP TEGRA_GPIO_PT3
42 #define PM269_SD_WP -1
43
44 static void (*wifi_status_cb)(int card_present, void *dev_id);
45 static void *wifi_status_cb_devid;
46 static int cardhu_wifi_status_register(void (*callback)(int , void *), void *);
47
48 static int cardhu_wifi_reset(int on);
49 static int cardhu_wifi_power(int on);
50 static int cardhu_wifi_set_carddetect(int val);
51
52 static struct wifi_platform_data cardhu_wifi_control = {
53         .set_power      = cardhu_wifi_power,
54         .set_reset      = cardhu_wifi_reset,
55         .set_carddetect = cardhu_wifi_set_carddetect,
56 };
57
58 static struct resource wifi_resource[] = {
59         [0] = {
60                 .name   = "bcm4329_wlan_irq",
61                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE,
62         },
63 };
64
65 static struct platform_device cardhu_wifi_device = {
66         .name           = "bcm4329_wlan",
67         .id             = 1,
68         .num_resources  = 1,
69         .resource       = wifi_resource,
70         .dev            = {
71                 .platform_data = &cardhu_wifi_control,
72         },
73 };
74
75 static struct resource sdhci_resource0[] = {
76         [0] = {
77                 .start  = INT_SDMMC1,
78                 .end    = INT_SDMMC1,
79                 .flags  = IORESOURCE_IRQ,
80         },
81         [1] = {
82                 .start  = TEGRA_SDMMC1_BASE,
83                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
84                 .flags  = IORESOURCE_MEM,
85         },
86 };
87
88 static struct resource sdhci_resource2[] = {
89         [0] = {
90                 .start  = INT_SDMMC3,
91                 .end    = INT_SDMMC3,
92                 .flags  = IORESOURCE_IRQ,
93         },
94         [1] = {
95                 .start  = TEGRA_SDMMC3_BASE,
96                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
97                 .flags  = IORESOURCE_MEM,
98         },
99 };
100
101 static struct resource sdhci_resource3[] = {
102         [0] = {
103                 .start  = INT_SDMMC4,
104                 .end    = INT_SDMMC4,
105                 .flags  = IORESOURCE_IRQ,
106         },
107         [1] = {
108                 .start  = TEGRA_SDMMC4_BASE,
109                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
110                 .flags  = IORESOURCE_MEM,
111         },
112 };
113
114 #ifdef CONFIG_MMC_EMBEDDED_SDIO
115 static struct embedded_sdio_data embedded_sdio_data2 = {
116         .cccr   = {
117                 .sdio_vsn       = 2,
118                 .multi_block    = 1,
119                 .low_speed      = 0,
120                 .wide_bus       = 0,
121                 .high_power     = 1,
122                 .high_speed     = 1,
123         },
124         .cis  = {
125                 .vendor         = 0x02d0,
126                 .device         = 0x4329,
127         },
128 };
129 #endif
130
131 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
132         .mmc_data = {
133                 .register_status_notify = cardhu_wifi_status_register,
134 #ifdef CONFIG_MMC_EMBEDDED_SDIO
135                 .embedded_sdio = &embedded_sdio_data2,
136 #endif
137                 .built_in = 0,
138                 .ocr_mask = MMC_OCR_1V8_MASK,
139         },
140 #ifndef CONFIG_MMC_EMBEDDED_SDIO
141         .pm_flags = MMC_PM_KEEP_POWER,
142 #endif
143         .cd_gpio = -1,
144         .wp_gpio = -1,
145         .power_gpio = -1,
146         .tap_delay = 0x0F,
147         .ddr_clk_limit = 41000000,
148 /*      .is_voltage_switch_supported = false,
149         .vdd_rail_name = NULL,
150         .slot_rail_name = NULL,
151         .vdd_max_uv = -1,
152         .vdd_min_uv = -1,
153         .max_clk = 0,
154         .is_8bit_supported = false, */
155 };
156
157 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
158         .cd_gpio = CARDHU_SD_CD,
159         .wp_gpio = CARDHU_SD_WP,
160         .power_gpio = -1,
161         .tap_delay = 0x0F,
162         .ddr_clk_limit = 41000000,
163 /*      .is_voltage_switch_supported = true,
164         .vdd_rail_name = "vddio_sdmmc1",
165         .slot_rail_name = "vddio_sd_slot",
166         .vdd_max_uv = 3320000,
167         .vdd_min_uv = 3280000,
168         .max_clk = 208000000,
169         .is_8bit_supported = false, */
170 };
171
172 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
173         .cd_gpio = -1,
174         .wp_gpio = -1,
175         .power_gpio = -1,
176         .is_8bit = 1,
177         .tap_delay = 0x0F,
178         .ddr_clk_limit = 41000000,
179         .mmc_data = {
180                 .built_in = 1,
181         }
182 /*      .is_voltage_switch_supported = false,
183         .vdd_rail_name = NULL,
184         .slot_rail_name = NULL,
185         .vdd_max_uv = -1,
186         .vdd_min_uv = -1,
187         .max_clk = 48000000,
188         .is_8bit_supported = true, */
189 };
190
191 static struct platform_device tegra_sdhci_device0 = {
192         .name           = "sdhci-tegra",
193         .id             = 0,
194         .resource       = sdhci_resource0,
195         .num_resources  = ARRAY_SIZE(sdhci_resource0),
196         .dev = {
197                 .platform_data = &tegra_sdhci_platform_data0,
198         },
199 };
200
201 static struct platform_device tegra_sdhci_device2 = {
202         .name           = "sdhci-tegra",
203         .id             = 2,
204         .resource       = sdhci_resource2,
205         .num_resources  = ARRAY_SIZE(sdhci_resource2),
206         .dev = {
207                 .platform_data = &tegra_sdhci_platform_data2,
208         },
209 };
210
211 static struct platform_device tegra_sdhci_device3 = {
212         .name           = "sdhci-tegra",
213         .id             = 3,
214         .resource       = sdhci_resource3,
215         .num_resources  = ARRAY_SIZE(sdhci_resource3),
216         .dev = {
217                 .platform_data = &tegra_sdhci_platform_data3,
218         },
219 };
220
221 static int cardhu_wifi_status_register(
222                 void (*callback)(int card_present, void *dev_id),
223                 void *dev_id)
224 {
225         if (wifi_status_cb)
226                 return -EAGAIN;
227         wifi_status_cb = callback;
228         wifi_status_cb_devid = dev_id;
229         return 0;
230 }
231
232 static int cardhu_wifi_set_carddetect(int val)
233 {
234         pr_debug("%s: %d\n", __func__, val);
235         if (wifi_status_cb)
236                 wifi_status_cb(val, wifi_status_cb_devid);
237         else
238                 pr_warning("%s: Nobody to notify\n", __func__);
239         return 0;
240 }
241
242 static int cardhu_wifi_power(int on)
243 {
244         struct tegra_io_dpd *sd_dpd;
245
246         pr_debug("%s: %d\n", __func__, on);
247
248         /*
249          * FIXME : we need to revisit IO DPD code
250          * on how should multiple pins under DPD get controlled
251          *
252          * cardhu GPIO WLAN enable is part of SDMMC3 pin group
253          */
254         sd_dpd = tegra_io_dpd_get(&tegra_sdhci_device2.dev);
255         if (sd_dpd) {
256                 mutex_lock(&sd_dpd->delay_lock);
257                 tegra_io_dpd_disable(sd_dpd);
258                 mutex_unlock(&sd_dpd->delay_lock);
259         }
260         gpio_set_value(CARDHU_WLAN_PWR, on);
261         mdelay(100);
262         gpio_set_value(CARDHU_WLAN_RST, on);
263         mdelay(200);
264         if (sd_dpd) {
265                 mutex_lock(&sd_dpd->delay_lock);
266                 tegra_io_dpd_enable(sd_dpd);
267                 mutex_unlock(&sd_dpd->delay_lock);
268         }
269
270         return 0;
271 }
272
273 static int cardhu_wifi_reset(int on)
274 {
275         pr_debug("%s: do nothing\n", __func__);
276         return 0;
277 }
278
279 static int __init cardhu_wifi_init(void)
280 {
281         int rc;
282
283         rc = gpio_request(CARDHU_WLAN_PWR, "wlan_power");
284         if (rc)
285                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
286         rc = gpio_request(CARDHU_WLAN_RST, "wlan_rst");
287         if (rc)
288                 pr_err("WLAN_RST gpio request failed:%d\n", rc);
289         rc = gpio_request(CARDHU_WLAN_WOW, "bcmsdh_sdmmc");
290         if (rc)
291                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
292
293         rc = gpio_direction_output(CARDHU_WLAN_PWR, 0);
294         if (rc)
295                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
296         gpio_direction_output(CARDHU_WLAN_RST, 0);
297         if (rc)
298                 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
299         rc = gpio_direction_input(CARDHU_WLAN_WOW);
300         if (rc)
301                 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
302
303         wifi_resource[0].start = wifi_resource[0].end =
304                 gpio_to_irq(TEGRA_GPIO_PO4);
305
306         platform_device_register(&cardhu_wifi_device);
307         return 0;
308 }
309
310 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
311 static int __init cardhu_wifi_prepower(void)
312 {
313         if (!machine_is_cardhu())
314                 return 0;
315
316         cardhu_wifi_power(1);
317
318         return 0;
319 }
320
321 subsys_initcall_sync(cardhu_wifi_prepower);
322 #endif
323
324 int __init cardhu_sdhci_init(void)
325 {
326         struct board_info board_info;
327         tegra_get_board_info(&board_info);
328         if ((board_info.board_id == BOARD_PM269) ||
329                 (board_info.board_id == BOARD_E1257) ||
330                 (board_info.board_id == BOARD_PM305) ||
331                 (board_info.board_id == BOARD_PM311)) {
332                         tegra_sdhci_platform_data0.wp_gpio = PM269_SD_WP;
333                         tegra_sdhci_platform_data2.max_clk_limit = 12000000;
334         }
335
336         platform_device_register(&tegra_sdhci_device3);
337         platform_device_register(&tegra_sdhci_device2);
338         platform_device_register(&tegra_sdhci_device0);
339
340         cardhu_wifi_init();
341         return 0;
342 }