3bfcc0ec1db96dd7fa0dab0d1684c4a3c6629e8c
[linux-2.6.git] / arch / arm / mach-tegra / board-kai-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-kai-sdhci.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  * Copyright (C) 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/delay.h>
21 #include <linux/gpio.h>
22 #include <linux/clk.h>
23 #include <linux/err.h>
24 #include <linux/mmc/host.h>
25 #include <linux/wl12xx.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-kai.h"
36
37 #define KAI_SD_CD       TEGRA_GPIO_PI5
38 #define KAI_WLAN_EN     TEGRA_GPIO_PD3
39 #define KAI_WLAN_IRQ    TEGRA_GPIO_PV1
40
41 static void (*wifi_status_cb)(int card_present, void *dev_id);
42 static void *wifi_status_cb_devid;
43 static int kai_wifi_power(int power_on);
44 static int kai_wifi_set_carddetect(int val);
45
46 static int kai_wifi_status_register(
47                 void (*callback)(int card_present, void *dev_id),
48                 void *dev_id)
49 {
50         if (wifi_status_cb)
51                 return -EAGAIN;
52         wifi_status_cb = callback;
53         wifi_status_cb_devid = dev_id;
54         return 0;
55 }
56
57
58 static struct wl12xx_platform_data kai_wlan_data __initdata = {
59         .board_ref_clock = WL12XX_REFCLOCK_26,
60         .board_tcxo_clock = 1,
61         .set_power = kai_wifi_power,
62         .set_carddetect = kai_wifi_set_carddetect,
63 };
64
65 static struct resource sdhci_resource0[] = {
66         [0] = {
67                 .start  = INT_SDMMC1,
68                 .end    = INT_SDMMC1,
69                 .flags  = IORESOURCE_IRQ,
70         },
71         [1] = {
72                 .start  = TEGRA_SDMMC1_BASE,
73                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
74                 .flags  = IORESOURCE_MEM,
75         },
76 };
77
78 static struct resource sdhci_resource2[] = {
79         [0] = {
80                 .start  = INT_SDMMC3,
81                 .end    = INT_SDMMC3,
82                 .flags  = IORESOURCE_IRQ,
83         },
84         [1] = {
85                 .start  = TEGRA_SDMMC3_BASE,
86                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
87                 .flags  = IORESOURCE_MEM,
88         },
89 };
90
91 static struct resource sdhci_resource3[] = {
92         [0] = {
93                 .start  = INT_SDMMC4,
94                 .end    = INT_SDMMC4,
95                 .flags  = IORESOURCE_IRQ,
96         },
97         [1] = {
98                 .start  = TEGRA_SDMMC4_BASE,
99                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
100                 .flags  = IORESOURCE_MEM,
101         },
102 };
103
104
105 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
106         .mmc_data = {
107                 .register_status_notify = kai_wifi_status_register,
108                 .built_in = 0,
109                 .ocr_mask = MMC_OCR_1V8_MASK,
110         },
111 #ifndef CONFIG_MMC_EMBEDDED_SDIO
112         .pm_flags = MMC_PM_KEEP_POWER,
113 #endif
114         .cd_gpio = -1,
115         .wp_gpio = -1,
116         .power_gpio = -1,
117         .tap_delay = 0x0F,
118         .ddr_clk_limit = 41000000,
119 /*      .is_voltage_switch_supported = false,
120         .vdd_rail_name = NULL,
121         .slot_rail_name = NULL,
122         .vdd_max_uv = -1,
123         .vdd_min_uv = -1,
124         .max_clk = 0,
125         .is_8bit_supported = false, */
126         /* .max_clk = 25000000, */
127 };
128
129 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
130         .cd_gpio = KAI_SD_CD,
131         .wp_gpio = -1,
132         .power_gpio = -1,
133         .tap_delay = 0x0F,
134         .ddr_clk_limit = 41000000,
135 /*      .is_voltage_switch_supported = true,
136         .vdd_rail_name = "vddio_sdmmc1",
137         .slot_rail_name = "vddio_sd_slot",
138         .vdd_max_uv = 3320000,
139         .vdd_min_uv = 3280000,
140         .max_clk = 208000000,
141         .is_8bit_supported = false, */
142 };
143
144 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
145         .cd_gpio = -1,
146         .wp_gpio = -1,
147         .power_gpio = -1,
148         .is_8bit = 1,
149         .tap_delay = 0x0F,
150         .ddr_clk_limit = 41000000,
151         .mmc_data = {
152                 .built_in = 1,
153         }
154 /*      .is_voltage_switch_supported = false,
155         .vdd_rail_name = NULL,
156         .slot_rail_name = NULL,
157         .vdd_max_uv = -1,
158         .vdd_min_uv = -1,
159         .max_clk = 48000000,
160         .is_8bit_supported = true, */
161 };
162
163 static struct platform_device tegra_sdhci_device0 = {
164         .name           = "sdhci-tegra",
165         .id             = 0,
166         .resource       = sdhci_resource0,
167         .num_resources  = ARRAY_SIZE(sdhci_resource0),
168         .dev = {
169                 .platform_data = &tegra_sdhci_platform_data0,
170         },
171 };
172
173 static struct platform_device tegra_sdhci_device2 = {
174         .name           = "sdhci-tegra",
175         .id             = 2,
176         .resource       = sdhci_resource2,
177         .num_resources  = ARRAY_SIZE(sdhci_resource2),
178         .dev = {
179                 .platform_data = &tegra_sdhci_platform_data2,
180         },
181 };
182
183 static struct platform_device tegra_sdhci_device3 = {
184         .name           = "sdhci-tegra",
185         .id             = 3,
186         .resource       = sdhci_resource3,
187         .num_resources  = ARRAY_SIZE(sdhci_resource3),
188         .dev = {
189                 .platform_data = &tegra_sdhci_platform_data3,
190         },
191 };
192
193 static int kai_wifi_set_carddetect(int val)
194 {
195         pr_debug("%s: %d\n", __func__, val);
196         if (wifi_status_cb)
197                 wifi_status_cb(val, wifi_status_cb_devid);
198         else
199         pr_warning("%s: Nobody to notify\n", __func__);
200         return 0;
201 }
202
203 static int kai_wifi_power(int power_on)
204 {
205         struct tegra_io_dpd *sd_dpd;
206         pr_err("Powering %s wifi\n", (power_on ? "on" : "off"));
207
208         /*
209          * FIXME : we need to revisit IO DPD code
210          * on how should multiple pins under DPD get controlled
211          *
212          * kai GPIO WLAN enable is part of SDMMC3 pin group
213          */
214         sd_dpd = tegra_io_dpd_get(&tegra_sdhci_device2.dev);
215         if (sd_dpd) {
216                 mutex_lock(&sd_dpd->delay_lock);
217                 tegra_io_dpd_disable(sd_dpd);
218                 mutex_unlock(&sd_dpd->delay_lock);
219         }
220         if (power_on) {
221                 gpio_set_value(KAI_WLAN_EN, 1);
222                 mdelay(15);
223                 gpio_set_value(KAI_WLAN_EN, 0);
224                 mdelay(1);
225                 gpio_set_value(KAI_WLAN_EN, 1);
226                 mdelay(70);
227         } else {
228                 gpio_set_value(KAI_WLAN_EN, 0);
229         }
230         if (sd_dpd) {
231                 mutex_lock(&sd_dpd->delay_lock);
232                 tegra_io_dpd_enable(sd_dpd);
233                 mutex_unlock(&sd_dpd->delay_lock);
234         }
235
236         return 0;
237 }
238
239 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
240 static int __init kai_wifi_prepower(void)
241 {
242         if (!machine_is_kai())
243                 return 0;
244
245         kai_wifi_power(1);
246
247         return 0;
248 }
249
250 subsys_initcall_sync(kai_wifi_prepower);
251 #endif
252
253 static int __init kai_wifi_init(void)
254 {
255         int rc;
256
257         rc = gpio_request(KAI_WLAN_EN, "wl12xx");
258         if (rc)
259                 pr_err("WLAN_EN gpio request failed:%d\n", rc);
260
261         rc = gpio_request(KAI_WLAN_IRQ, "wl12xx");
262         if (rc)
263                 pr_err("WLAN_IRQ gpio request failed:%d\n", rc);
264
265         rc = gpio_direction_output(KAI_WLAN_EN, 0);
266         if (rc)
267                 pr_err("WLAN_EN gpio direction configuration failed:%d\n", rc);
268
269         rc = gpio_direction_input(KAI_WLAN_IRQ);
270         if (rc)
271                 pr_err("WLAN_IRQ gpio direction configuration failed:%d\n", rc);
272
273         kai_wlan_data.irq = gpio_to_irq(KAI_WLAN_IRQ);
274         if (wl12xx_set_platform_data(&kai_wlan_data))
275                 pr_err("Error setting wl12xx data\n");
276
277         return 0;
278 }
279
280 int __init kai_sdhci_init(void)
281 {
282         platform_device_register(&tegra_sdhci_device3);
283         platform_device_register(&tegra_sdhci_device2);
284         platform_device_register(&tegra_sdhci_device0);
285
286         kai_wifi_init();
287         return 0;
288 }