57d299c9e74704d1952be96d032ff7384324a6c5
[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 #include "tegra-board-id.h"
41
42 #define ARDBEG_WLAN_RST TEGRA_GPIO_PCC5
43 #define ARDBEG_WLAN_PWR TEGRA_GPIO_PX7
44 #define ARDBEG_WLAN_WOW TEGRA_GPIO_PU5
45
46 #define ARDBEG_SD_CD    TEGRA_GPIO_PV2
47
48 static void (*wifi_status_cb)(int card_present, void *dev_id);
49 static void *wifi_status_cb_devid;
50 static int ardbeg_wifi_status_register(void (*callback)(int , void *), void *);
51
52 static int ardbeg_wifi_reset(int on);
53 static int ardbeg_wifi_power(int on);
54 static int ardbeg_wifi_set_carddetect(int val);
55
56 static struct wifi_platform_data ardbeg_wifi_control = {
57         .set_power      = ardbeg_wifi_power,
58         .set_reset      = ardbeg_wifi_reset,
59         .set_carddetect = ardbeg_wifi_set_carddetect,
60 };
61
62 static struct resource wifi_resource[] = {
63         [0] = {
64                 .name   = "bcm4329_wlan_irq",
65                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
66                                 | IORESOURCE_IRQ_SHAREABLE,
67         },
68 };
69
70 static struct platform_device ardbeg_wifi_device = {
71         .name           = "bcm4329_wlan",
72         .id             = 1,
73         .num_resources  = 1,
74         .resource       = wifi_resource,
75         .dev            = {
76                 .platform_data = &ardbeg_wifi_control,
77         },
78 };
79
80 static struct resource mrvl_wifi_resource[] = {
81         [0] = {
82                 .name   = "mrvl_wlan_irq",
83                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE,
84         },
85 };
86
87 static struct platform_device marvell_wifi_device = {
88         .name           = "mrvl_wlan",
89         .id             = 1,
90         .num_resources  = 1,
91         .resource       = mrvl_wifi_resource,
92         .dev            = {
93                 .platform_data = &ardbeg_wifi_control,
94         },
95 };
96
97 static struct resource sdhci_resource0[] = {
98         [0] = {
99                 .start  = INT_SDMMC1,
100                 .end    = INT_SDMMC1,
101                 .flags  = IORESOURCE_IRQ,
102         },
103         [1] = {
104                 .start  = TEGRA_SDMMC1_BASE,
105                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
106                 .flags  = IORESOURCE_MEM,
107         },
108 };
109
110 static struct resource sdhci_resource2[] = {
111         [0] = {
112                 .start  = INT_SDMMC3,
113                 .end    = INT_SDMMC3,
114                 .flags  = IORESOURCE_IRQ,
115         },
116         [1] = {
117                 .start  = TEGRA_SDMMC3_BASE,
118                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
119                 .flags  = IORESOURCE_MEM,
120         },
121 };
122
123 static struct resource sdhci_resource3[] = {
124         [0] = {
125                 .start  = INT_SDMMC4,
126                 .end    = INT_SDMMC4,
127                 .flags  = IORESOURCE_IRQ,
128         },
129         [1] = {
130                 .start  = TEGRA_SDMMC4_BASE,
131                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
132                 .flags  = IORESOURCE_MEM,
133         },
134 };
135
136 #ifdef CONFIG_MMC_EMBEDDED_SDIO
137 static struct embedded_sdio_data embedded_sdio_data0 = {
138         .cccr   = {
139                 .sdio_vsn       = 2,
140                 .multi_block    = 1,
141                 .low_speed      = 0,
142                 .wide_bus       = 0,
143                 .high_power     = 1,
144                 .high_speed     = 1,
145         },
146         .cis  = {
147                 .vendor  = 0x02d0,
148                 .device  = 0x4329,
149         },
150 };
151 #endif
152
153 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
154         .mmc_data = {
155                 .register_status_notify = ardbeg_wifi_status_register,
156 #ifdef CONFIG_MMC_EMBEDDED_SDIO
157                 .embedded_sdio = &embedded_sdio_data0,
158 #endif
159                 .built_in = 0,
160                 .ocr_mask = MMC_OCR_1V8_MASK,
161         },
162         .cd_gpio = -1,
163         .wp_gpio = -1,
164         .power_gpio = -1,
165         .tap_delay = 0,
166         .trim_delay = 0x2,
167         .ddr_clk_limit = 41000000,
168 /*FIXME: Enable UHS modes for WiFI */
169         .uhs_mask = MMC_UHS_MASK_SDR104 | MMC_UHS_MASK_SDR12 | MMC_UHS_MASK_SDR25 |
170                 MMC_UHS_MASK_DDR50 | MMC_UHS_MASK_SDR50,
171         .calib_3v3_offsets = 0x7676,
172         .calib_1v8_offsets = 0x7676,
173         .calib_1v8_offsets_uhs_modes = MMC_1V8_CALIB_OFFSET_DDR50,
174 };
175
176 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
177         .cd_gpio = ARDBEG_SD_CD,
178         .wp_gpio = -1,
179         .power_gpio = -1,
180         .tap_delay = 0,
181         .trim_delay = 0x3,
182 /*FIXME: Enable UHS modes for SD */
183         .uhs_mask = MMC_UHS_MASK_SDR12 | MMC_UHS_MASK_SDR25 |
184                 MMC_UHS_MASK_SDR104 | MMC_UHS_MASK_DDR50 |
185                 MMC_UHS_MASK_SDR50,
186         .calib_3v3_offsets = 0x7676,
187         .calib_1v8_offsets = 0x7676,
188         .calib_1v8_offsets_uhs_modes = MMC_1V8_CALIB_OFFSET_DDR50,
189 };
190
191 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
192         .cd_gpio = -1,
193         .wp_gpio = -1,
194         .power_gpio = -1,
195         .is_8bit = 1,
196         .tap_delay = 0x4,
197         .trim_delay = 0x4,
198         .ddr_trim_delay = 0x4,
199         .mmc_data = {
200                 .built_in = 1,
201                 .ocr_mask = MMC_OCR_1V8_MASK,
202         },
203         .ddr_clk_limit = 51000000,
204         .max_clk_limit = 102000000,
205         .calib_3v3_offsets = 0x0202,
206         .calib_1v8_offsets = 0x0202,
207         .calib_1v8_offsets_uhs_modes = MMC_1V8_CALIB_OFFSET_DDR50 |
208                 MMC_1V8_CALIB_OFFSET_HS200,
209 };
210
211 static struct platform_device tegra_sdhci_device0 = {
212         .name           = "sdhci-tegra",
213         .id             = 0,
214         .resource       = sdhci_resource0,
215         .num_resources  = ARRAY_SIZE(sdhci_resource0),
216         .dev = {
217                 .platform_data = &tegra_sdhci_platform_data0,
218         },
219 };
220
221 static struct platform_device tegra_sdhci_device2 = {
222         .name           = "sdhci-tegra",
223         .id             = 2,
224         .resource       = sdhci_resource2,
225         .num_resources  = ARRAY_SIZE(sdhci_resource2),
226         .dev = {
227                 .platform_data = &tegra_sdhci_platform_data2,
228         },
229 };
230
231 static struct platform_device tegra_sdhci_device3 = {
232         .name           = "sdhci-tegra",
233         .id             = 3,
234         .resource       = sdhci_resource3,
235         .num_resources  = ARRAY_SIZE(sdhci_resource3),
236         .dev = {
237                 .platform_data = &tegra_sdhci_platform_data3,
238         },
239 };
240
241 static int ardbeg_wifi_status_register(
242                 void (*callback)(int card_present, void *dev_id),
243                 void *dev_id)
244 {
245         if (wifi_status_cb)
246                 return -EAGAIN;
247         wifi_status_cb = callback;
248         wifi_status_cb_devid = dev_id;
249         return 0;
250 }
251
252 static int ardbeg_wifi_set_carddetect(int val)
253 {
254         pr_debug("%s: %d\n", __func__, val);
255         if (wifi_status_cb)
256                 wifi_status_cb(val, wifi_status_cb_devid);
257         else
258                 pr_warn("%s: Nobody to notify\n", __func__);
259         return 0;
260 }
261
262 static int ardbeg_wifi_power(int on)
263 {
264         pr_err("%s: %d\n", __func__, on);
265
266         gpio_set_value(ARDBEG_WLAN_PWR, on);
267         gpio_set_value(ARDBEG_WLAN_RST, on);
268         mdelay(100);
269
270         return 0;
271 }
272
273 static int ardbeg_wifi_reset(int on)
274 {
275         pr_debug("%s: do nothing\n", __func__);
276         return 0;
277 }
278
279 static int __init ardbeg_wifi_init(void)
280 {
281         int rc;
282
283         rc = gpio_request(ARDBEG_WLAN_PWR, "wlan_power");
284         if (rc)
285                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
286         rc = gpio_request(ARDBEG_WLAN_RST, "wlan_rst");
287         if (rc)
288                 pr_err("WLAN_RST gpio request failed:%d\n", rc);
289         rc = gpio_request(ARDBEG_WLAN_WOW, "bcmsdh_sdmmc");
290         if (rc)
291                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
292
293         rc = gpio_direction_output(ARDBEG_WLAN_PWR, 0);
294         if (rc)
295                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
296         rc = gpio_direction_output(ARDBEG_WLAN_RST, 0);
297         if (rc)
298                 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
299
300         rc = gpio_direction_input(ARDBEG_WLAN_WOW);
301         if (rc)
302                 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
303
304         wifi_resource[0].start = wifi_resource[0].end =
305                 gpio_to_irq(ARDBEG_WLAN_WOW);
306
307         platform_device_register(&ardbeg_wifi_device);
308
309         mrvl_wifi_resource[0].start = mrvl_wifi_resource[0].end =
310                 gpio_to_irq(ARDBEG_WLAN_WOW);
311         platform_device_register(&marvell_wifi_device);
312
313         return 0;
314 }
315
316 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
317 static int __init ardbeg_wifi_prepower(void)
318 {
319         if (!of_machine_is_compatible("nvidia,ardbeg") &&
320                 !of_machine_is_compatible("nvidia,laguna") &&
321                 !of_machine_is_compatible("nvidia,tn8"))
322                 return 0;
323         ardbeg_wifi_power(1);
324
325         return 0;
326 }
327
328 subsys_initcall_sync(ardbeg_wifi_prepower);
329 #endif
330
331 int __init ardbeg_sdhci_init(void)
332 {
333         int nominal_core_mv;
334         int min_vcore_override_mv;
335         int boot_vcore_mv;
336         struct board_info board_info;
337
338         nominal_core_mv =
339                 tegra_dvfs_rail_get_nominal_millivolts(tegra_core_rail);
340         if (nominal_core_mv) {
341                 tegra_sdhci_platform_data0.nominal_vcore_mv = nominal_core_mv;
342                 tegra_sdhci_platform_data2.nominal_vcore_mv = nominal_core_mv;
343                 tegra_sdhci_platform_data3.nominal_vcore_mv = nominal_core_mv;
344         }
345         min_vcore_override_mv =
346                 tegra_dvfs_rail_get_override_floor(tegra_core_rail);
347         if (min_vcore_override_mv) {
348                 tegra_sdhci_platform_data0.min_vcore_override_mv =
349                         min_vcore_override_mv;
350                 tegra_sdhci_platform_data2.min_vcore_override_mv =
351                         min_vcore_override_mv;
352                 tegra_sdhci_platform_data3.min_vcore_override_mv =
353                         min_vcore_override_mv;
354         }
355         boot_vcore_mv = tegra_dvfs_rail_get_boot_level(tegra_core_rail);
356         if (boot_vcore_mv) {
357                 tegra_sdhci_platform_data0.boot_vcore_mv = boot_vcore_mv;
358                 tegra_sdhci_platform_data2.boot_vcore_mv = boot_vcore_mv;
359                 tegra_sdhci_platform_data3.boot_vcore_mv = boot_vcore_mv;
360         }
361
362         tegra_get_board_info(&board_info);
363         if (board_info.board_id == BOARD_E1780) {
364                 tegra_sdhci_platform_data3.max_clk_limit = 200000000;
365                 tegra_sdhci_platform_data2.max_clk_limit = 204000000;
366         } else {
367                 tegra_sdhci_platform_data3.uhs_mask = MMC_MASK_HS200;
368         }
369
370         platform_device_register(&tegra_sdhci_device3);
371         platform_device_register(&tegra_sdhci_device2);
372         platform_device_register(&tegra_sdhci_device0);
373         ardbeg_wifi_init();
374
375         return 0;
376 }