arm: tegra: ardbeg/damore: disable UHS mode for WiFi
[linux-3.10.git] / arch / arm / mach-tegra / board-ardbeg-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-ardbeg-sdhci.c
3  *
4  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <linux/resource.h>
20 #include <linux/platform_device.h>
21 #include <linux/wlan_plat.h>
22 #include <linux/delay.h>
23 #include <linux/gpio.h>
24 #include <linux/clk.h>
25 #include <linux/err.h>
26 #include <linux/mmc/host.h>
27 #include <linux/wl12xx.h>
28 #include <linux/platform_data/mmc-sdhci-tegra.h>
29 #include <linux/mfd/max77660/max77660-core.h>
30
31 #include <asm/mach-types.h>
32 #include <mach/irqs.h>
33 #include <mach/gpio-tegra.h>
34
35 #include "gpio-names.h"
36 #include "board.h"
37 #include "board-ardbeg.h"
38 #include "dvfs.h"
39 #include "iomap.h"
40
41 #define ARDBEG_WLAN_RST TEGRA_GPIO_PCC5
42 #define ARDBEG_WLAN_PWR TEGRA_GPIO_PX7
43 #define ARDBEG_WLAN_WOW TEGRA_GPIO_PU5
44
45 #define ARDBEG_SD_CD    TEGRA_GPIO_PV2
46
47 static void (*wifi_status_cb)(int card_present, void *dev_id);
48 static void *wifi_status_cb_devid;
49 static int ardbeg_wifi_status_register(void (*callback)(int , void *), void *);
50
51 static int ardbeg_wifi_reset(int on);
52 static int ardbeg_wifi_power(int on);
53 static int ardbeg_wifi_set_carddetect(int val);
54
55 static struct wifi_platform_data ardbeg_wifi_control = {
56         .set_power      = ardbeg_wifi_power,
57         .set_reset      = ardbeg_wifi_reset,
58         .set_carddetect = ardbeg_wifi_set_carddetect,
59 };
60
61 static struct resource wifi_resource[] = {
62         [0] = {
63                 .name   = "bcm4329_wlan_irq",
64                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
65                                 | IORESOURCE_IRQ_SHAREABLE,
66         },
67 };
68
69 static struct platform_device ardbeg_wifi_device = {
70         .name           = "bcm4329_wlan",
71         .id             = 1,
72         .num_resources  = 1,
73         .resource       = wifi_resource,
74         .dev            = {
75                 .platform_data = &ardbeg_wifi_control,
76         },
77 };
78
79 static struct resource sdhci_resource0[] = {
80         [0] = {
81                 .start  = INT_SDMMC1,
82                 .end    = INT_SDMMC1,
83                 .flags  = IORESOURCE_IRQ,
84         },
85         [1] = {
86                 .start  = TEGRA_SDMMC1_BASE,
87                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
88                 .flags  = IORESOURCE_MEM,
89         },
90 };
91
92 static struct resource sdhci_resource2[] = {
93         [0] = {
94                 .start  = INT_SDMMC3,
95                 .end    = INT_SDMMC3,
96                 .flags  = IORESOURCE_IRQ,
97         },
98         [1] = {
99                 .start  = TEGRA_SDMMC3_BASE,
100                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
101                 .flags  = IORESOURCE_MEM,
102         },
103 };
104
105 static struct resource sdhci_resource3[] = {
106         [0] = {
107                 .start  = INT_SDMMC4,
108                 .end    = INT_SDMMC4,
109                 .flags  = IORESOURCE_IRQ,
110         },
111         [1] = {
112                 .start  = TEGRA_SDMMC4_BASE,
113                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
114                 .flags  = IORESOURCE_MEM,
115         },
116 };
117
118 #ifdef CONFIG_MMC_EMBEDDED_SDIO
119 static struct embedded_sdio_data embedded_sdio_data0 = {
120         .cccr   = {
121                 .sdio_vsn       = 2,
122                 .multi_block    = 1,
123                 .low_speed      = 0,
124                 .wide_bus       = 0,
125                 .high_power     = 1,
126                 .high_speed     = 1,
127         },
128         .cis  = {
129                 .vendor  = 0x02d0,
130                 .device  = 0x4329,
131         },
132 };
133 #endif
134
135 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
136         .mmc_data = {
137                 .register_status_notify = ardbeg_wifi_status_register,
138 #ifdef CONFIG_MMC_EMBEDDED_SDIO
139                 .embedded_sdio = &embedded_sdio_data0,
140 #endif
141                 .built_in = 0,
142                 .ocr_mask = MMC_OCR_1V8_MASK,
143         },
144         .cd_gpio = -1,
145         .wp_gpio = -1,
146         .power_gpio = -1,
147         .tap_delay = 0,
148         .trim_delay = 0x2,
149         .ddr_clk_limit = 41000000,
150 /*FIXME: Enable UHS modes for WiFI */
151         .uhs_mask = MMC_UHS_MASK_SDR104 | MMC_UHS_MASK_SDR12 | MMC_UHS_MASK_SDR25 |
152                 MMC_UHS_MASK_DDR50 | MMC_UHS_MASK_SDR50,
153 };
154
155 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
156         .cd_gpio = ARDBEG_SD_CD,
157         .wp_gpio = -1,
158         .power_gpio = -1,
159         .tap_delay = 0,
160         .trim_delay = 0x3,
161 /*FIXME: Enable UHS modes for SD */
162         .uhs_mask = MMC_UHS_MASK_SDR12 | MMC_UHS_MASK_SDR25 |
163                 MMC_UHS_MASK_SDR104 |
164                 MMC_UHS_MASK_DDR50 | MMC_UHS_MASK_SDR50,
165 /*      .max_clk = 12000000, */
166 };
167
168 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
169         .cd_gpio = -1,
170         .wp_gpio = -1,
171         .power_gpio = -1,
172         .is_8bit = 1,
173         .tap_delay = 0x4,
174         .trim_delay = 0x4,
175         .ddr_trim_delay = 0x4,
176         .mmc_data = {
177                 .built_in = 1,
178                 .ocr_mask = MMC_OCR_1V8_MASK,
179         },
180         .uhs_mask = MMC_MASK_HS200,
181         .ddr_clk_limit = 51000000,
182         .max_clk_limit = 102000000,
183 /*      .max_clk = 12000000, */
184 };
185
186 static struct platform_device tegra_sdhci_device0 = {
187         .name           = "sdhci-tegra",
188         .id             = 0,
189         .resource       = sdhci_resource0,
190         .num_resources  = ARRAY_SIZE(sdhci_resource0),
191         .dev = {
192                 .platform_data = &tegra_sdhci_platform_data0,
193         },
194 };
195
196 static struct platform_device tegra_sdhci_device2 = {
197         .name           = "sdhci-tegra",
198         .id             = 2,
199         .resource       = sdhci_resource2,
200         .num_resources  = ARRAY_SIZE(sdhci_resource2),
201         .dev = {
202                 .platform_data = &tegra_sdhci_platform_data2,
203         },
204 };
205
206 static struct platform_device tegra_sdhci_device3 = {
207         .name           = "sdhci-tegra",
208         .id             = 3,
209         .resource       = sdhci_resource3,
210         .num_resources  = ARRAY_SIZE(sdhci_resource3),
211         .dev = {
212                 .platform_data = &tegra_sdhci_platform_data3,
213         },
214 };
215
216 static int ardbeg_wifi_status_register(
217                 void (*callback)(int card_present, void *dev_id),
218                 void *dev_id)
219 {
220         if (wifi_status_cb)
221                 return -EAGAIN;
222         wifi_status_cb = callback;
223         wifi_status_cb_devid = dev_id;
224         return 0;
225 }
226
227 static int ardbeg_wifi_set_carddetect(int val)
228 {
229         pr_debug("%s: %d\n", __func__, val);
230         if (wifi_status_cb)
231                 wifi_status_cb(val, wifi_status_cb_devid);
232         else
233                 pr_warn("%s: Nobody to notify\n", __func__);
234         return 0;
235 }
236
237 static int ardbeg_wifi_power(int on)
238 {
239         pr_err("%s: %d\n", __func__, on);
240
241         gpio_set_value(ARDBEG_WLAN_PWR, on);
242         gpio_set_value(ARDBEG_WLAN_RST, on);
243         mdelay(100);
244
245         return 0;
246 }
247
248 static int ardbeg_wifi_reset(int on)
249 {
250         pr_debug("%s: do nothing\n", __func__);
251         return 0;
252 }
253
254 static int __init ardbeg_wifi_init(void)
255 {
256         int rc;
257
258         rc = gpio_request(ARDBEG_WLAN_PWR, "wlan_power");
259         if (rc)
260                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
261         rc = gpio_request(ARDBEG_WLAN_RST, "wlan_rst");
262         if (rc)
263                 pr_err("WLAN_RST gpio request failed:%d\n", rc);
264         rc = gpio_request(ARDBEG_WLAN_WOW, "bcmsdh_sdmmc");
265         if (rc)
266                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
267
268         rc = gpio_direction_output(ARDBEG_WLAN_PWR, 0);
269         if (rc)
270                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
271         rc = gpio_direction_output(ARDBEG_WLAN_RST, 0);
272         if (rc)
273                 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
274
275         rc = gpio_direction_input(ARDBEG_WLAN_WOW);
276         if (rc)
277                 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
278
279         wifi_resource[0].start = wifi_resource[0].end =
280                 gpio_to_irq(ARDBEG_WLAN_WOW);
281
282         platform_device_register(&ardbeg_wifi_device);
283         return 0;
284 }
285
286 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
287 static int __init ardbeg_wifi_prepower(void)
288 {
289         if (!of_machine_is_compatible("nvidia,ardbeg") &&
290                 !of_machine_is_compatible("nvidia,laguna") &&
291                 !of_machine_is_compatible("nvidia,tn8"))
292                 return 0;
293         ardbeg_wifi_power(1);
294
295         return 0;
296 }
297
298 subsys_initcall_sync(ardbeg_wifi_prepower);
299 #endif
300
301 int __init ardbeg_sdhci_init(void)
302 {
303         int nominal_core_mv;
304         int min_vcore_override_mv;
305         int boot_vcore_mv;
306
307         nominal_core_mv =
308                 tegra_dvfs_rail_get_nominal_millivolts(tegra_core_rail);
309         if (nominal_core_mv) {
310                 tegra_sdhci_platform_data0.nominal_vcore_mv = nominal_core_mv;
311                 tegra_sdhci_platform_data2.nominal_vcore_mv = nominal_core_mv;
312                 tegra_sdhci_platform_data3.nominal_vcore_mv = nominal_core_mv;
313         }
314         min_vcore_override_mv =
315                 tegra_dvfs_rail_get_override_floor(tegra_core_rail);
316         if (min_vcore_override_mv) {
317                 tegra_sdhci_platform_data0.min_vcore_override_mv =
318                         min_vcore_override_mv;
319                 tegra_sdhci_platform_data2.min_vcore_override_mv =
320                         min_vcore_override_mv;
321                 tegra_sdhci_platform_data3.min_vcore_override_mv =
322                         min_vcore_override_mv;
323         }
324         boot_vcore_mv = tegra_dvfs_rail_get_boot_level(tegra_core_rail);
325         if (boot_vcore_mv) {
326                 tegra_sdhci_platform_data0.boot_vcore_mv = boot_vcore_mv;
327                 tegra_sdhci_platform_data2.boot_vcore_mv = boot_vcore_mv;
328                 tegra_sdhci_platform_data3.boot_vcore_mv = boot_vcore_mv;
329         }
330         platform_device_register(&tegra_sdhci_device3);
331         platform_device_register(&tegra_sdhci_device2);
332         platform_device_register(&tegra_sdhci_device0);
333         ardbeg_wifi_init();
334
335         return 0;
336 }