ARM: tegra: tegratab: adding more comment
[linux-2.6.git] / arch / arm / mach-tegra / board-tegratab-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-tegratab-sdhci.c
3  *
4  * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
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/delay.h>
20 #include <linux/gpio.h>
21 #include <linux/clk.h>
22 #include <linux/err.h>
23 #include <linux/regulator/consumer.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/gpio-tegra.h>
31 #include <mach/io_dpd.h>
32 #include <linux/wl12xx.h>
33
34 #include "tegra-board-id.h"
35 #include "gpio-names.h"
36 #include "board.h"
37 #include "board-tegratab.h"
38 #include "dvfs.h"
39
40 #define TEGRATAB_SD_CD  TEGRA_GPIO_PV2
41 #define TEGRATAB_SD_WP  TEGRA_GPIO_PQ4
42 #define TEGRATAB_WLAN_PWR       TEGRA_GPIO_PCC5
43 #define TEGRATAB_WLAN_RST       TEGRA_GPIO_PX7
44 #define TEGRATAB_WLAN_WOW       TEGRA_GPIO_PU5
45 #if defined(CONFIG_WLCORE_EDP_SUPPORT)
46 #define ON 808 /* 808.236 mW */
47 #define OFF 0
48 static unsigned int wl_states[] = {ON, OFF};
49 #endif
50
51 static void (*wifi_status_cb)(int card_present, void *dev_id);
52 static void *wifi_status_cb_devid;
53 static int tegratab_wifi_status_register(void (*callback)(int , void *),
54                                         void *);
55
56 static int tegratab_wifi_power(int on);
57 static int tegratab_wifi_set_carddetect(int val);
58
59 static struct wl12xx_platform_data tegratab_wl12xx_wlan_data __initdata = {
60         .board_ref_clock = WL12XX_REFCLOCK_26,
61         .board_tcxo_clock = 1,
62         .set_power = tegratab_wifi_power,
63         .set_carddetect = tegratab_wifi_set_carddetect,
64 #if defined(CONFIG_WLCORE_EDP_SUPPORT)
65         .edp_info = {
66                 .client_info = {
67                         .name = "wl_edp_client",
68                         .states = wl_states,
69                         .num_states = ARRAY_SIZE(wl_states),
70                         .e0_index = 0,
71                         .priority = EDP_MAX_PRIO,
72                 },
73                 .registered = false,
74         },
75 #endif
76 };
77
78 static struct resource sdhci_resource0[] = {
79         [0] = {
80                 .start  = INT_SDMMC1,
81                 .end    = INT_SDMMC1,
82                 .flags  = IORESOURCE_IRQ,
83         },
84         [1] = {
85                 .start  = TEGRA_SDMMC1_BASE,
86                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
87                 .flags  = IORESOURCE_MEM,
88         },
89 };
90
91 static struct resource sdhci_resource2[] = {
92         [0] = {
93                 .start  = INT_SDMMC3,
94                 .end    = INT_SDMMC3,
95                 .flags  = IORESOURCE_IRQ,
96         },
97         [1] = {
98                 .start  = TEGRA_SDMMC3_BASE,
99                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
100                 .flags  = IORESOURCE_MEM,
101         },
102 };
103
104 static struct resource sdhci_resource3[] = {
105         [0] = {
106                 .start  = INT_SDMMC4,
107                 .end    = INT_SDMMC4,
108                 .flags  = IORESOURCE_IRQ,
109         },
110         [1] = {
111                 .start  = TEGRA_SDMMC4_BASE,
112                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
113                 .flags  = IORESOURCE_MEM,
114         },
115 };
116
117 #ifdef CONFIG_MMC_EMBEDDED_SDIO
118 static struct embedded_sdio_data embedded_sdio_data0 = {
119         .cccr   = {
120                 .sdio_vsn       = 2,
121                 .multi_block    = 1,
122                 .low_speed      = 0,
123                 .wide_bus       = 0,
124                 .high_power     = 1,
125                 .high_speed     = 1,
126         },
127         .cis  = {
128                 .vendor  = 0x02d0,
129                 .device  = 0x4329,
130         },
131 };
132 #endif
133
134 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
135         .mmc_data = {
136                 .register_status_notify = tegratab_wifi_status_register,
137 #ifdef CONFIG_MMC_EMBEDDED_SDIO
138                 .embedded_sdio = &embedded_sdio_data0,
139 #endif
140                 .built_in = 0,
141                 .ocr_mask = MMC_OCR_1V8_MASK,
142         },
143 #ifndef CONFIG_MMC_EMBEDDED_SDIO
144         .pm_flags = MMC_PM_KEEP_POWER,
145 #endif
146         .cd_gpio = -1,
147         .wp_gpio = -1,
148         .power_gpio = -1,
149         .tap_delay = 0x2,
150         .trim_delay = 0x2,
151         .ddr_clk_limit = 41000000,
152         .uhs_mask = MMC_UHS_MASK_SDR104 |
153                 MMC_UHS_MASK_DDR50,
154 };
155
156 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
157         .cd_gpio = TEGRATAB_SD_CD,
158         .wp_gpio = TEGRATAB_SD_WP,
159         .power_gpio = -1,
160         .tap_delay = 0x3,
161         .trim_delay = 0x3,
162         .ddr_clk_limit = 41000000,
163         .max_clk_limit = 156000000,
164         .mmc_data = {
165                 .ocr_mask = MMC_OCR_2V8_MASK,
166         },
167         .uhs_mask = MMC_UHS_MASK_DDR50,
168         .edp_support = true,
169         .edp_states = {966, 0},
170         .power_off_rail = true,
171 };
172
173 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
174         .cd_gpio = -1,
175         .wp_gpio = -1,
176         .power_gpio = -1,
177         .is_8bit = 1,
178         .tap_delay = 0x5,
179         .trim_delay = 0xA,
180         .ddr_clk_limit = 41000000,
181         .max_clk_limit = 156000000,
182         .mmc_data = {
183                 .built_in = 1,
184                 .ocr_mask = MMC_OCR_1V8_MASK,
185         },
186         .edp_support = true,
187         .edp_states = {966, 0},
188 };
189
190 static struct platform_device tegra_sdhci_device0 = {
191         .name           = "sdhci-tegra",
192         .id             = 0,
193         .resource       = sdhci_resource0,
194         .num_resources  = ARRAY_SIZE(sdhci_resource0),
195         .dev = {
196                 .platform_data = &tegra_sdhci_platform_data0,
197         },
198 };
199
200 static struct platform_device tegra_sdhci_device2 = {
201         .name           = "sdhci-tegra",
202         .id             = 2,
203         .resource       = sdhci_resource2,
204         .num_resources  = ARRAY_SIZE(sdhci_resource2),
205         .dev = {
206                 .platform_data = &tegra_sdhci_platform_data2,
207         },
208 };
209
210 static struct platform_device tegra_sdhci_device3 = {
211         .name           = "sdhci-tegra",
212         .id             = 3,
213         .resource       = sdhci_resource3,
214         .num_resources  = ARRAY_SIZE(sdhci_resource3),
215         .dev = {
216                 .platform_data = &tegra_sdhci_platform_data3,
217         },
218 };
219
220 static int tegratab_wifi_status_register(
221                 void (*callback)(int card_present, void *dev_id),
222                 void *dev_id)
223 {
224         if (wifi_status_cb)
225                 return -EAGAIN;
226         wifi_status_cb = callback;
227         wifi_status_cb_devid = dev_id;
228         return 0;
229 }
230
231 static int tegratab_wifi_set_carddetect(int val)
232 {
233         pr_debug("%s: %d\n", __func__, val);
234         if (wifi_status_cb)
235                 wifi_status_cb(val, wifi_status_cb_devid);
236         else
237                 pr_warning("%s: Nobody to notify\n", __func__);
238         return 0;
239 }
240
241 static int tegratab_wifi_power(int on)
242 {
243         pr_debug("%s: %d\n", __func__, on);
244
245         if (on) {
246                 gpio_set_value(TEGRATAB_WLAN_RST, 1);
247                 mdelay(100);
248                 gpio_set_value(TEGRATAB_WLAN_RST, 0);
249                 mdelay(100);
250                 gpio_set_value(TEGRATAB_WLAN_RST, 1);
251                 mdelay(100);
252                 gpio_set_value(TEGRATAB_WLAN_PWR, 1);
253                 mdelay(200);
254         } else {
255                 gpio_set_value(TEGRATAB_WLAN_RST, 0);
256                 mdelay(100);
257                 gpio_set_value(TEGRATAB_WLAN_PWR, 0);
258         }
259
260         return 0;
261 }
262
263 static int __init tegratab_wifi_init(void)
264 {
265         int rc;
266
267         rc = gpio_request(TEGRATAB_WLAN_PWR, "wlan_power");
268         if (rc)
269                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
270         rc = gpio_request(TEGRATAB_WLAN_RST, "wlan_rst");
271         if (rc)
272                 pr_err("WLAN_RST gpio request failed:%d\n", rc);
273         rc = gpio_request(TEGRATAB_WLAN_WOW, "bcmsdh_sdmmc");
274         if (rc)
275                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
276
277         rc = gpio_direction_output(TEGRATAB_WLAN_PWR, 0);
278         if (rc)
279                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
280         rc = gpio_direction_output(TEGRATAB_WLAN_RST, 0);
281         if (rc)
282                 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
283         rc = gpio_direction_input(TEGRATAB_WLAN_WOW);
284         if (rc)
285                 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
286         tegratab_wl12xx_wlan_data.irq = gpio_to_irq(TEGRATAB_WLAN_WOW);
287                 wl12xx_set_platform_data(&tegratab_wl12xx_wlan_data);
288         return 0;
289 }
290
291 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
292 static int __init tegratab_wifi_prepower(void)
293 {
294         if (!machine_is_tegratab())
295                 return 0;
296
297 #ifdef CONFIG_ANDROID
298         /* In charger mode, don't power on wifi to lower power consumption */
299         if (get_androidboot_mode_charger())
300                 return 0;
301 #endif
302
303         tegratab_wifi_power(1);
304
305         return 0;
306 }
307
308 subsys_initcall_sync(tegratab_wifi_prepower);
309 #endif
310
311 int __init tegratab_sdhci_init(void)
312 {
313         int nominal_core_mv;
314         int min_vcore_override_mv;
315         int boot_vcore_mv;
316         struct board_info board_info;
317         nominal_core_mv =
318                 tegra_dvfs_rail_get_nominal_millivolts(tegra_core_rail);
319         if (nominal_core_mv) {
320                 tegra_sdhci_platform_data0.nominal_vcore_mv = nominal_core_mv;
321                 tegra_sdhci_platform_data2.nominal_vcore_mv = nominal_core_mv;
322                 tegra_sdhci_platform_data3.nominal_vcore_mv = nominal_core_mv;
323         }
324         min_vcore_override_mv =
325                 tegra_dvfs_rail_get_override_floor(tegra_core_rail);
326         if (min_vcore_override_mv) {
327                 tegra_sdhci_platform_data0.min_vcore_override_mv =
328                         min_vcore_override_mv;
329                 tegra_sdhci_platform_data2.min_vcore_override_mv =
330                         min_vcore_override_mv;
331                 tegra_sdhci_platform_data3.min_vcore_override_mv =
332                         min_vcore_override_mv;
333         }
334         boot_vcore_mv = tegra_dvfs_rail_get_boot_level(tegra_core_rail);
335         if (boot_vcore_mv) {
336                 tegra_sdhci_platform_data0.boot_vcore_mv = boot_vcore_mv;
337                 tegra_sdhci_platform_data2.boot_vcore_mv = boot_vcore_mv;
338                 tegra_sdhci_platform_data3.boot_vcore_mv = boot_vcore_mv;
339         }
340
341         tegra_get_board_info(&board_info);
342         if (board_info.board_id == BOARD_P1640)
343                 tegra_sdhci_platform_data2.wp_gpio = -1;
344         if ((tegra_sdhci_platform_data3.uhs_mask & MMC_MASK_HS200)
345         && (!(tegra_sdhci_platform_data3.uhs_mask & MMC_UHS_MASK_DDR50)))
346                 tegra_sdhci_platform_data3.trim_delay = 0;
347         platform_device_register(&tegra_sdhci_device3);
348
349 #ifdef CONFIG_ANDROID
350         /* In charger mode, don't register wifi and external sd. */
351         if (get_androidboot_mode_charger())
352                 return 0;
353 #endif
354
355         platform_device_register(&tegra_sdhci_device2);
356         platform_device_register(&tegra_sdhci_device0);
357         tegratab_wifi_init();
358         return 0;
359 }