7de81a8d64d854d4b121498be3df54d076807ca6
[linux-3.10.git] / arch / arm / mach-tegra / board-loki-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-loki-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-loki.h"
38 #include "iomap.h"
39
40 #define LOKI_WLAN_RST   TEGRA_GPIO_PR3
41 #define LOKI_WLAN_PWR   TEGRA_GPIO_PCC5
42 #define LOKI_WLAN_WOW   TEGRA_GPIO_PU5
43
44 #define LOKI_SD_CD      TEGRA_GPIO_PV2
45
46 static void (*wifi_status_cb)(int card_present, void *dev_id);
47 static void *wifi_status_cb_devid;
48 static int loki_wifi_status_register(void (*callback)(int , void *), void *);
49
50 static int loki_wifi_reset(int on);
51 static int loki_wifi_power(int on);
52 static int loki_wifi_set_carddetect(int val);
53
54 static struct wifi_platform_data loki_wifi_control = {
55         .set_power      = loki_wifi_power,
56         .set_reset      = loki_wifi_reset,
57         .set_carddetect = loki_wifi_set_carddetect,
58 };
59
60 static struct resource wifi_resource[] = {
61         [0] = {
62                 .name   = "bcm4329_wlan_irq",
63                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
64                                 | IORESOURCE_IRQ_SHAREABLE,
65         },
66 };
67
68 static struct platform_device loki_wifi_device = {
69         .name           = "bcm4329_wlan",
70         .id             = 1,
71         .num_resources  = 1,
72         .resource       = wifi_resource,
73         .dev            = {
74                 .platform_data = &loki_wifi_control,
75         },
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 = loki_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         .cd_gpio = -1,
144         .wp_gpio = -1,
145         .power_gpio = -1,
146         .tap_delay = 0,
147         .trim_delay = 0x2,
148         .ddr_clk_limit = 41000000,
149         .uhs_mask = MMC_UHS_MASK_SDR104 |
150                 /* FIXME: Enable UHS mode */
151                 MMC_UHS_MASK_SDR12 | MMC_UHS_MASK_SDR25 |
152                 MMC_UHS_MASK_DDR50 | MMC_UHS_MASK_SDR50,
153         .calib_3v3_offsets = 0x7676,
154         .calib_1v8_offsets = 0x7676,
155         .calib_1v8_offsets_uhs_modes = MMC_1V8_CALIB_OFFSET_DDR50,
156 };
157
158 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
159         .cd_gpio = LOKI_SD_CD,
160         .wp_gpio = -1,
161         .power_gpio = -1,
162         .tap_delay = 0,
163         .trim_delay = 0x3,
164         .uhs_mask = MMC_UHS_MASK_SDR104 |
165                 /* FIXME: Enable UHS mode */
166                 MMC_UHS_MASK_SDR12 | MMC_UHS_MASK_SDR25 |
167                 MMC_UHS_MASK_DDR50 | MMC_UHS_MASK_SDR50,
168         .calib_3v3_offsets = 0x7676,
169         .calib_1v8_offsets = 0x7676,
170         .calib_1v8_offsets_uhs_modes = MMC_1V8_CALIB_OFFSET_DDR50,
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 = 0x4,
179         .trim_delay = 0x4,
180         .ddr_trim_delay = 0x4,
181         .mmc_data = {
182                 .built_in = 1,
183                 .ocr_mask = MMC_OCR_1V8_MASK,
184         },
185         .uhs_mask = MMC_MASK_HS200,
186         .ddr_clk_limit = 51000000,
187         .max_clk_limit = 102000000,
188         .calib_3v3_offsets = 0x0202,
189         .calib_1v8_offsets = 0x0202,
190         .calib_1v8_offsets_uhs_modes = MMC_1V8_CALIB_OFFSET_DDR50 |
191                 MMC_1V8_CALIB_OFFSET_HS200,
192
193 };
194
195 static struct platform_device tegra_sdhci_device0 = {
196         .name           = "sdhci-tegra",
197         .id             = 0,
198         .resource       = sdhci_resource0,
199         .num_resources  = ARRAY_SIZE(sdhci_resource0),
200         .dev = {
201                 .platform_data = &tegra_sdhci_platform_data0,
202         },
203 };
204
205 static struct platform_device tegra_sdhci_device2 = {
206         .name           = "sdhci-tegra",
207         .id             = 2,
208         .resource       = sdhci_resource2,
209         .num_resources  = ARRAY_SIZE(sdhci_resource2),
210         .dev = {
211                 .platform_data = &tegra_sdhci_platform_data2,
212         },
213 };
214
215 static struct platform_device tegra_sdhci_device3 = {
216         .name           = "sdhci-tegra",
217         .id             = 3,
218         .resource       = sdhci_resource3,
219         .num_resources  = ARRAY_SIZE(sdhci_resource3),
220         .dev = {
221                 .platform_data = &tegra_sdhci_platform_data3,
222         },
223 };
224
225 static int loki_wifi_status_register(
226                 void (*callback)(int card_present, void *dev_id),
227                 void *dev_id)
228 {
229         if (wifi_status_cb)
230                 return -EAGAIN;
231         wifi_status_cb = callback;
232         wifi_status_cb_devid = dev_id;
233         return 0;
234 }
235
236 static int loki_wifi_set_carddetect(int val)
237 {
238         pr_debug("%s: %d\n", __func__, val);
239         if (wifi_status_cb)
240                 wifi_status_cb(val, wifi_status_cb_devid);
241         else
242                 pr_warn("%s: Nobody to notify\n", __func__);
243         return 0;
244 }
245
246 static struct regulator *loki_vdd_com_3v3;
247 static struct regulator *loki_vddio_com_1v8;
248
249 #define LOKI_VDD_WIFI_3V3 "avdd"
250 #define LOKI_VDD_WIFI_1V8 "dvdd"
251
252 static int loki_wifi_regulator_enable(void)
253 {
254         int ret = 0;
255
256         /* Enable COM's vdd_com_3v3 regulator*/
257         if (IS_ERR_OR_NULL(loki_vdd_com_3v3)) {
258                 loki_vdd_com_3v3 = regulator_get(&loki_wifi_device.dev,
259                                         LOKI_VDD_WIFI_3V3);
260                 if (IS_ERR_OR_NULL(loki_vdd_com_3v3)) {
261                         pr_err("Couldn't get regulator "
262                                 LOKI_VDD_WIFI_3V3 "\n");
263                         return PTR_ERR(loki_vdd_com_3v3);
264                 }
265
266                 ret = regulator_enable(loki_vdd_com_3v3);
267                 if (ret < 0) {
268                         pr_err("Couldn't enable regulator "
269                                 LOKI_VDD_WIFI_3V3 "\n");
270                         regulator_put(loki_vdd_com_3v3);
271                         loki_vdd_com_3v3 = NULL;
272                         return ret;
273                 }
274         }
275
276         /* Enable COM's vddio_com_1v8 regulator*/
277         if (IS_ERR_OR_NULL(loki_vddio_com_1v8)) {
278                 loki_vddio_com_1v8 = regulator_get(&loki_wifi_device.dev,
279                         LOKI_VDD_WIFI_1V8);
280                 if (IS_ERR_OR_NULL(loki_vddio_com_1v8)) {
281                         pr_err("Couldn't get regulator "
282                                 LOKI_VDD_WIFI_1V8 "\n");
283                         regulator_disable(loki_vdd_com_3v3);
284
285                         regulator_put(loki_vdd_com_3v3);
286                         loki_vdd_com_3v3 = NULL;
287                         return PTR_ERR(loki_vddio_com_1v8);
288                 }
289
290                 ret = regulator_enable(loki_vddio_com_1v8);
291                 if (ret < 0) {
292                         pr_err("Couldn't enable regulator "
293                                 LOKI_VDD_WIFI_1V8 "\n");
294                         regulator_put(loki_vddio_com_1v8);
295                         loki_vddio_com_1v8 = NULL;
296
297                         regulator_disable(loki_vdd_com_3v3);
298                         regulator_put(loki_vdd_com_3v3);
299                         loki_vdd_com_3v3 = NULL;
300                         return ret;
301                 }
302         }
303
304         return ret;
305 }
306
307 static void loki_wifi_regulator_disable(void)
308 {
309         /* Disable COM's vdd_com_3v3 regulator*/
310         if (!IS_ERR_OR_NULL(loki_vdd_com_3v3)) {
311                 regulator_disable(loki_vdd_com_3v3);
312                 regulator_put(loki_vdd_com_3v3);
313                 loki_vdd_com_3v3 = NULL;
314         }
315
316         /* Disable COM's vddio_com_1v8 regulator*/
317         if (!IS_ERR_OR_NULL(loki_vddio_com_1v8)) {
318                 regulator_disable(loki_vddio_com_1v8);
319                 regulator_put(loki_vddio_com_1v8);
320                 loki_vddio_com_1v8 = NULL;
321         }
322 }
323
324 static int loki_wifi_power(int on)
325 {
326         int ret = 0;
327
328         pr_err("%s: %d\n", __func__, on);
329
330         /* Enable COM's regulators on wi-fi poer on*/
331         if (on == 1) {
332                 ret = loki_wifi_regulator_enable();
333                 if (ret < 0) {
334                         pr_err("Failed to enable COM regulators\n");
335                         return ret;
336                 }
337         }
338
339         gpio_set_value(LOKI_WLAN_PWR, on);
340         gpio_set_value(LOKI_WLAN_RST, on);
341         mdelay(100);
342
343         /* Disable COM's regulators on wi-fi poer off*/
344         if (on != 1) {
345                 pr_debug("Disabling COM regulators\n");
346                 loki_wifi_regulator_disable();
347         }
348
349         return 0;
350 }
351
352 static int loki_wifi_reset(int on)
353 {
354         pr_debug("%s: do nothing\n", __func__);
355         return 0;
356 }
357
358 static int __init loki_wifi_init(void)
359 {
360         int rc;
361
362         rc = gpio_request(LOKI_WLAN_PWR, "wlan_power");
363         if (rc)
364                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
365         rc = gpio_request(LOKI_WLAN_RST, "wlan_rst");
366         if (rc)
367                 pr_err("WLAN_RST gpio request failed:%d\n", rc);
368         rc = gpio_request(LOKI_WLAN_WOW, "bcmsdh_sdmmc");
369         if (rc)
370                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
371
372         rc = gpio_direction_output(LOKI_WLAN_PWR, 0);
373         if (rc)
374                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
375         rc = gpio_direction_output(LOKI_WLAN_RST, 0);
376         if (rc)
377                 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
378
379         rc = gpio_direction_input(LOKI_WLAN_WOW);
380         if (rc)
381                 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
382
383         wifi_resource[0].start = wifi_resource[0].end =
384                 gpio_to_irq(LOKI_WLAN_WOW);
385
386         platform_device_register(&loki_wifi_device);
387         return 0;
388 }
389
390 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
391 static int __init loki_wifi_prepower(void)
392 {
393         if (!of_machine_is_compatible("nvidia,loki"))
394                 return 0;
395         loki_wifi_power(1);
396
397         return 0;
398 }
399
400 subsys_initcall_sync(loki_wifi_prepower);
401 #endif
402
403 int __init loki_sdhci_init(void)
404 {
405         platform_device_register(&tegra_sdhci_device3);
406         platform_device_register(&tegra_sdhci_device2);
407         platform_device_register(&tegra_sdhci_device0);
408         loki_wifi_init();
409
410         return 0;
411 }