blob: dc1976900d9198521e22c5c2f9cf0d36118637a9 [file] [log] [blame]
aghuge6c0b8db2012-07-31 10:48:37 +05301/*
2 * arch/arm/mach-tegra/board-dalmore-sdhci.c
3 *
Pavan Kunapuli78b9d102013-02-13 15:40:50 +05304 * Copyright (C) 2010 Google, Inc.
Pavan Kunapulie4b00c82013-02-15 04:04:04 +05305 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
aghuge6c0b8db2012-07-31 10:48:37 +05306 *
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>
naveenkfbcfe182012-08-29 14:56:35 +053020#include <linux/wlan_plat.h>
aghuge6c0b8db2012-07-31 10:48:37 +053021#include <linux/delay.h>
22#include <linux/gpio.h>
23#include <linux/clk.h>
24#include <linux/err.h>
Mohan Tb9a67fe2012-09-13 19:46:07 +053025#include <linux/regulator/consumer.h>
aghuge6c0b8db2012-07-31 10:48:37 +053026#include <linux/mmc/host.h>
27#include <linux/wl12xx.h>
28
29#include <asm/mach-types.h>
30#include <mach/irqs.h>
31#include <mach/iomap.h>
32#include <mach/sdhci.h>
naveenkfbcfe182012-08-29 14:56:35 +053033#include<mach/gpio-tegra.h>
34#include <mach/io_dpd.h>
aghuge6c0b8db2012-07-31 10:48:37 +053035
Naveen Kumar Arepalli9f6f9a12013-01-28 22:33:00 +053036#include "tegra-board-id.h"
aghuge6c0b8db2012-07-31 10:48:37 +053037#include "gpio-names.h"
38#include "board.h"
39#include "board-dalmore.h"
Pavan Kunapuli78b9d102013-02-13 15:40:50 +053040#include "dvfs.h"
Mohan Tb9a67fe2012-09-13 19:46:07 +053041
naveenkfbcfe182012-08-29 14:56:35 +053042#define DALMORE_WLAN_PWR TEGRA_GPIO_PCC5
43#define DALMORE_WLAN_RST TEGRA_GPIO_PX7
44#define DALMORE_WLAN_WOW TEGRA_GPIO_PU5
naveenk11fe9042012-09-25 21:43:16 +053045#define DALMORE_SD_CD TEGRA_GPIO_PV2
naveenkfbcfe182012-08-29 14:56:35 +053046static void (*wifi_status_cb)(int card_present, void *dev_id);
47static void *wifi_status_cb_devid;
48static int dalmore_wifi_status_register(void (*callback)(int , void *), void *);
49
50static int dalmore_wifi_reset(int on);
51static int dalmore_wifi_power(int on);
52static int dalmore_wifi_set_carddetect(int val);
53
54static struct wifi_platform_data dalmore_wifi_control = {
55 .set_power = dalmore_wifi_power,
56 .set_reset = dalmore_wifi_reset,
57 .set_carddetect = dalmore_wifi_set_carddetect,
58};
59
60static 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
68static struct platform_device dalmore_wifi_device = {
69 .name = "bcm4329_wlan",
70 .id = 1,
71 .num_resources = 1,
72 .resource = wifi_resource,
73 .dev = {
74 .platform_data = &dalmore_wifi_control,
75 },
76};
77
78static 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
91static 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
104static 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
118static 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 = {
Mohan Tb9a67fe2012-09-13 19:46:07 +0530128 .vendor = 0x02d0,
129 .device = 0x4329,
naveenkfbcfe182012-08-29 14:56:35 +0530130 },
131};
132#endif
133
134static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
135 .mmc_data = {
136 .register_status_notify = dalmore_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,
Pavan Kunapulif509df52012-10-11 16:10:52 +0530149 .tap_delay = 0x2,
150 .trim_delay = 0x2,
naveenkfbcfe182012-08-29 14:56:35 +0530151 .ddr_clk_limit = 41000000,
Naveen Kumar Arepalli4f5e6d12013-01-21 11:34:27 +0530152 .max_clk_limit = 82000000,
Pavan Kunapulia38407d2013-02-13 15:28:31 +0530153 .uhs_mask = MMC_UHS_MASK_DDR50,
rrajk3a198422013-02-20 20:24:30 +0530154 .edp_support = false,
naveenkfbcfe182012-08-29 14:56:35 +0530155};
156
157static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
naveenk11fe9042012-09-25 21:43:16 +0530158 .cd_gpio = DALMORE_SD_CD,
naveenkfbcfe182012-08-29 14:56:35 +0530159 .wp_gpio = -1,
160 .power_gpio = -1,
Pavan Kunapulif509df52012-10-11 16:10:52 +0530161 .tap_delay = 0x3,
162 .trim_delay = 0x3,
naveenkfbcfe182012-08-29 14:56:35 +0530163 .ddr_clk_limit = 41000000,
Naveen Kumar Arepalli4f5e6d12013-01-21 11:34:27 +0530164 .max_clk_limit = 82000000,
Pavan Kunapulia38407d2013-02-13 15:28:31 +0530165 .uhs_mask = MMC_UHS_MASK_DDR50,
rrajk3a198422013-02-20 20:24:30 +0530166 .edp_support = true,
167 .edp_states = {966, 0},
Ken Chang49563302013-03-19 17:40:40 +0800168 .power_off_rail = true,
naveenkfbcfe182012-08-29 14:56:35 +0530169};
170
171static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
172 .cd_gpio = -1,
173 .wp_gpio = -1,
174 .power_gpio = -1,
175 .is_8bit = 1,
Pavan Kunapulif509df52012-10-11 16:10:52 +0530176 .tap_delay = 0x5,
Naveen Kumar Arepallie893f5a2013-03-20 16:34:01 +0530177 .trim_delay = 0xA,
naveenkfbcfe182012-08-29 14:56:35 +0530178 .ddr_clk_limit = 41000000,
Pavan Kunapulie4b00c82013-02-15 04:04:04 +0530179 .max_clk_limit = 156000000,
naveenkfbcfe182012-08-29 14:56:35 +0530180 .mmc_data = {
181 .built_in = 1,
Naveen Kumar Arepallia845b9a2012-11-09 12:09:00 +0530182 .ocr_mask = MMC_OCR_1V8_MASK,
Pavan Kunapuli02a716d2013-02-13 16:49:54 +0530183 },
rrajk3a198422013-02-20 20:24:30 +0530184 .edp_support = true,
185 .edp_states = {966, 0},
naveenkfbcfe182012-08-29 14:56:35 +0530186};
187
188static struct platform_device tegra_sdhci_device0 = {
189 .name = "sdhci-tegra",
190 .id = 0,
191 .resource = sdhci_resource0,
192 .num_resources = ARRAY_SIZE(sdhci_resource0),
193 .dev = {
194 .platform_data = &tegra_sdhci_platform_data0,
195 },
196};
197
198static struct platform_device tegra_sdhci_device2 = {
199 .name = "sdhci-tegra",
200 .id = 2,
201 .resource = sdhci_resource2,
202 .num_resources = ARRAY_SIZE(sdhci_resource2),
203 .dev = {
204 .platform_data = &tegra_sdhci_platform_data2,
205 },
206};
207
208static struct platform_device tegra_sdhci_device3 = {
209 .name = "sdhci-tegra",
210 .id = 3,
211 .resource = sdhci_resource3,
212 .num_resources = ARRAY_SIZE(sdhci_resource3),
213 .dev = {
214 .platform_data = &tegra_sdhci_platform_data3,
215 },
216};
217
218static int dalmore_wifi_status_register(
219 void (*callback)(int card_present, void *dev_id),
220 void *dev_id)
221{
222 if (wifi_status_cb)
223 return -EAGAIN;
224 wifi_status_cb = callback;
225 wifi_status_cb_devid = dev_id;
226 return 0;
227}
228
229static int dalmore_wifi_set_carddetect(int val)
230{
231 pr_debug("%s: %d\n", __func__, val);
232 if (wifi_status_cb)
233 wifi_status_cb(val, wifi_status_cb_devid);
234 else
235 pr_warning("%s: Nobody to notify\n", __func__);
236 return 0;
237}
238
Mohan Tb9a67fe2012-09-13 19:46:07 +0530239static struct regulator *dalmore_vdd_com_3v3;
240static struct regulator *dalmore_vddio_com_1v8;
241#define DALMORE_VDD_WIFI_3V3 "vdd_wifi_3v3"
242#define DALMORE_VDD_WIFI_1V8 "vddio_wifi_1v8"
243
Mohan Tb9a67fe2012-09-13 19:46:07 +0530244static int dalmore_wifi_regulator_enable(void)
245{
246 int ret = 0;
247
248 /* Enable COM's vdd_com_3v3 regulator*/
249 if (IS_ERR_OR_NULL(dalmore_vdd_com_3v3)) {
Nagarjuna Kristam92065fb2012-10-26 13:57:28 +0530250 dalmore_vdd_com_3v3 = regulator_get(&dalmore_wifi_device.dev,
251 DALMORE_VDD_WIFI_3V3);
Mohan Tb9a67fe2012-09-13 19:46:07 +0530252 if (IS_ERR_OR_NULL(dalmore_vdd_com_3v3)) {
253 pr_err("Couldn't get regulator "
254 DALMORE_VDD_WIFI_3V3 "\n");
255 return PTR_ERR(dalmore_vdd_com_3v3);
256 }
257
258 ret = regulator_enable(dalmore_vdd_com_3v3);
259 if (ret < 0) {
260 pr_err("Couldn't enable regulator "
261 DALMORE_VDD_WIFI_3V3 "\n");
262 regulator_put(dalmore_vdd_com_3v3);
263 dalmore_vdd_com_3v3 = NULL;
264 return ret;
265 }
266 }
267
268 /* Enable COM's vddio_com_1v8 regulator*/
269 if (IS_ERR_OR_NULL(dalmore_vddio_com_1v8)) {
Nagarjuna Kristam92065fb2012-10-26 13:57:28 +0530270 dalmore_vddio_com_1v8 = regulator_get(&dalmore_wifi_device.dev,
Mohan Tb9a67fe2012-09-13 19:46:07 +0530271 DALMORE_VDD_WIFI_1V8);
272 if (IS_ERR_OR_NULL(dalmore_vddio_com_1v8)) {
273 pr_err("Couldn't get regulator "
274 DALMORE_VDD_WIFI_1V8 "\n");
275 regulator_disable(dalmore_vdd_com_3v3);
276
277 regulator_put(dalmore_vdd_com_3v3);
278 dalmore_vdd_com_3v3 = NULL;
279 return PTR_ERR(dalmore_vddio_com_1v8);
280 }
281
282 ret = regulator_enable(dalmore_vddio_com_1v8);
283 if (ret < 0) {
284 pr_err("Couldn't enable regulator "
285 DALMORE_VDD_WIFI_1V8 "\n");
286 regulator_put(dalmore_vddio_com_1v8);
287 dalmore_vddio_com_1v8 = NULL;
288
289 regulator_disable(dalmore_vdd_com_3v3);
290 regulator_put(dalmore_vdd_com_3v3);
291 dalmore_vdd_com_3v3 = NULL;
292 return ret;
293 }
294 }
295
296 return ret;
297}
298
299static void dalmore_wifi_regulator_disable(void)
300{
301 /* Disable COM's vdd_com_3v3 regulator*/
302 if (!IS_ERR_OR_NULL(dalmore_vdd_com_3v3)) {
303 regulator_disable(dalmore_vdd_com_3v3);
304 regulator_put(dalmore_vdd_com_3v3);
305 dalmore_vdd_com_3v3 = NULL;
306 }
307
308 /* Disable COM's vddio_com_1v8 regulator*/
309 if (!IS_ERR_OR_NULL(dalmore_vddio_com_1v8)) {
310 regulator_disable(dalmore_vddio_com_1v8);
311 regulator_put(dalmore_vddio_com_1v8);
312 dalmore_vddio_com_1v8 = NULL;
313 }
314}
315
naveenkfbcfe182012-08-29 14:56:35 +0530316static int dalmore_wifi_power(int on)
317{
Mohan Tb9a67fe2012-09-13 19:46:07 +0530318 int ret = 0;
naveenkfbcfe182012-08-29 14:56:35 +0530319
320 pr_debug("%s: %d\n", __func__, on);
Mohan Tb9a67fe2012-09-13 19:46:07 +0530321 /* Enable COM's regulators on wi-fi poer on*/
322 if (on == 1) {
323 ret = dalmore_wifi_regulator_enable();
324 if (ret < 0) {
325 pr_err("Failed to enable COM regulators\n");
326 return ret;
327 }
328 }
naveenkfbcfe182012-08-29 14:56:35 +0530329
naveenkfbcfe182012-08-29 14:56:35 +0530330 gpio_set_value(DALMORE_WLAN_PWR, on);
331 mdelay(100);
332 gpio_set_value(DALMORE_WLAN_RST, on);
333 mdelay(200);
naveenkfbcfe182012-08-29 14:56:35 +0530334
Mohan Tb9a67fe2012-09-13 19:46:07 +0530335 /* Disable COM's regulators on wi-fi poer off*/
336 if (on != 1) {
337 pr_debug("Disabling COM regulators\n");
338 dalmore_wifi_regulator_disable();
339 }
340
341 return ret;
naveenkfbcfe182012-08-29 14:56:35 +0530342}
343
344static int dalmore_wifi_reset(int on)
345{
346 pr_debug("%s: do nothing\n", __func__);
347 return 0;
348}
349
350static int __init dalmore_wifi_init(void)
351{
352 int rc;
353
354 rc = gpio_request(DALMORE_WLAN_PWR, "wlan_power");
355 if (rc)
356 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
357 rc = gpio_request(DALMORE_WLAN_RST, "wlan_rst");
358 if (rc)
359 pr_err("WLAN_RST gpio request failed:%d\n", rc);
360 rc = gpio_request(DALMORE_WLAN_WOW, "bcmsdh_sdmmc");
361 if (rc)
362 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
363
364 rc = gpio_direction_output(DALMORE_WLAN_PWR, 0);
365 if (rc)
366 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
367 gpio_direction_output(DALMORE_WLAN_RST, 0);
368 if (rc)
369 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
370 rc = gpio_direction_input(DALMORE_WLAN_WOW);
371 if (rc)
372 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
373
374 wifi_resource[0].start = wifi_resource[0].end =
Mohan Tb9a67fe2012-09-13 19:46:07 +0530375 gpio_to_irq(DALMORE_WLAN_WOW);
naveenkfbcfe182012-08-29 14:56:35 +0530376
377 platform_device_register(&dalmore_wifi_device);
378 return 0;
379}
380
381#ifdef CONFIG_TEGRA_PREPOWER_WIFI
382static int __init dalmore_wifi_prepower(void)
383{
384 if (!machine_is_dalmore())
385 return 0;
386
387 dalmore_wifi_power(1);
388
389 return 0;
390}
391
392subsys_initcall_sync(dalmore_wifi_prepower);
393#endif
394
395int __init dalmore_sdhci_init(void)
396{
Pavan Kunapuli78b9d102013-02-13 15:40:50 +0530397 int nominal_core_mv;
Pavan Kunapulie48887a2013-05-08 10:01:42 +0530398 int min_vcore_override_mv;
399
Pavan Kunapuli78b9d102013-02-13 15:40:50 +0530400 nominal_core_mv =
401 tegra_dvfs_rail_get_nominal_millivolts(tegra_core_rail);
402 if (nominal_core_mv) {
Pavan Kunapulie48887a2013-05-08 10:01:42 +0530403 tegra_sdhci_platform_data0.nominal_vcore_mv = nominal_core_mv;
404 tegra_sdhci_platform_data2.nominal_vcore_mv = nominal_core_mv;
405 tegra_sdhci_platform_data3.nominal_vcore_mv = nominal_core_mv;
406 }
407 min_vcore_override_mv =
408 tegra_dvfs_rail_get_override_floor(tegra_core_rail);
409 if (min_vcore_override_mv) {
410 tegra_sdhci_platform_data0.min_vcore_override_mv =
411 min_vcore_override_mv;
412 tegra_sdhci_platform_data2.min_vcore_override_mv =
413 min_vcore_override_mv;
414 tegra_sdhci_platform_data3.min_vcore_override_mv =
415 min_vcore_override_mv;
Pavan Kunapuli78b9d102013-02-13 15:40:50 +0530416 }
Naveen Kumar Arepalli3a1112b2013-05-03 11:35:25 +0530417 if ((tegra_sdhci_platform_data3.uhs_mask & MMC_MASK_HS200)
418 && (!(tegra_sdhci_platform_data3.uhs_mask &
419 MMC_UHS_MASK_DDR50)))
420 tegra_sdhci_platform_data3.trim_delay = 0;
Pavan Kunapulie48887a2013-05-08 10:01:42 +0530421
naveenkfbcfe182012-08-29 14:56:35 +0530422 platform_device_register(&tegra_sdhci_device3);
423 platform_device_register(&tegra_sdhci_device2);
424 platform_device_register(&tegra_sdhci_device0);
425 dalmore_wifi_init();
426 return 0;
427}