ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / board-pismo-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-pismo-sdhci.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
6  *
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 #include <linux/resource.h>
18 #include <linux/platform_device.h>
19 #include <linux/wlan_plat.h>
20 #include <linux/delay.h>
21 #include <linux/gpio.h>
22 #include <linux/clk.h>
23 #include <linux/err.h>
24 #include <linux/regulator/consumer.h>
25 #include <linux/mmc/host.h>
26 #include <linux/wl12xx.h>
27 #include <linux/platform_data/mmc-sdhci-tegra.h>
28
29 #include <asm/mach-types.h>
30 #include <mach/irqs.h>
31 #include <mach/gpio-tegra.h>
32 #include <mach/io_dpd.h>
33
34 #include "gpio-names.h"
35 #include "board.h"
36 #include "board-pismo.h"
37 #include "iomap.h"
38
39 #define PISMO_WLAN_PWR  TEGRA_GPIO_PCC5
40 #define PISMO_WLAN_RST  TEGRA_GPIO_PX7
41 #define PISMO_WLAN_WOW  TEGRA_GPIO_PU5
42 #define PISMO_SD_CD             TEGRA_GPIO_PV2
43 static void (*wifi_status_cb)(int card_present, void *dev_id);
44 static void *wifi_status_cb_devid;
45 static int pismo_wifi_status_register(void (*callback)(int , void *), void *);
46
47 static int pismo_wifi_reset(int on);
48 static int pismo_wifi_power(int on);
49 static int pismo_wifi_set_carddetect(int val);
50
51 static struct wifi_platform_data pismo_wifi_control = {
52         .set_power      = pismo_wifi_power,
53         .set_reset      = pismo_wifi_reset,
54         .set_carddetect = pismo_wifi_set_carddetect,
55 };
56
57 static struct resource wifi_resource[] = {
58         [0] = {
59                 .name   = "bcm4329_wlan_irq",
60                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
61                                 | IORESOURCE_IRQ_SHAREABLE,
62         },
63 };
64
65 static struct platform_device pismo_wifi_device = {
66         .name           = "bcm4329_wlan",
67         .id             = 1,
68         .num_resources  = 1,
69         .resource       = wifi_resource,
70         .dev            = {
71                 .platform_data = &pismo_wifi_control,
72         },
73 };
74
75 static struct resource sdhci_resource0[] = {
76         [0] = {
77                 .start  = INT_SDMMC1,
78                 .end    = INT_SDMMC1,
79                 .flags  = IORESOURCE_IRQ,
80         },
81         [1] = {
82                 .start  = TEGRA_SDMMC1_BASE,
83                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
84                 .flags  = IORESOURCE_MEM,
85         },
86 };
87
88 static struct resource sdhci_resource2[] = {
89         [0] = {
90                 .start  = INT_SDMMC3,
91                 .end    = INT_SDMMC3,
92                 .flags  = IORESOURCE_IRQ,
93         },
94         [1] = {
95                 .start  = TEGRA_SDMMC3_BASE,
96                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
97                 .flags  = IORESOURCE_MEM,
98         },
99 };
100
101 static struct resource sdhci_resource3[] = {
102         [0] = {
103                 .start  = INT_SDMMC4,
104                 .end    = INT_SDMMC4,
105                 .flags  = IORESOURCE_IRQ,
106         },
107         [1] = {
108                 .start  = TEGRA_SDMMC4_BASE,
109                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
110                 .flags  = IORESOURCE_MEM,
111         },
112 };
113
114 #ifdef CONFIG_MMC_EMBEDDED_SDIO
115 static struct embedded_sdio_data embedded_sdio_data0 = {
116         .cccr   = {
117                 .sdio_vsn       = 2,
118                 .multi_block    = 1,
119                 .low_speed      = 0,
120                 .wide_bus       = 0,
121                 .high_power     = 1,
122                 .high_speed     = 1,
123         },
124         .cis  = {
125                 .vendor  = 0x02d0,
126                 .device  = 0x4329,
127         },
128 };
129 #endif
130
131 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
132         .mmc_data = {
133                 .register_status_notify = pismo_wifi_status_register,
134 #ifdef CONFIG_MMC_EMBEDDED_SDIO
135                 .embedded_sdio = &embedded_sdio_data0,
136 #endif
137                 .built_in = 0,
138                 .ocr_mask = MMC_OCR_1V8_MASK,
139         },
140 #ifndef CONFIG_MMC_EMBEDDED_SDIO
141         .pm_flags = MMC_PM_KEEP_POWER,
142 #endif
143         .cd_gpio = -1,
144         .wp_gpio = -1,
145         .power_gpio = -1,
146         .tap_delay = 0x2,
147         .trim_delay = 0x2,
148         .ddr_clk_limit = 41000000,
149         .uhs_mask = MMC_UHS_MASK_SDR104 |
150                 MMC_UHS_MASK_DDR50,
151         .disable_clock_gate = true,
152 };
153
154 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
155         .cd_gpio = PISMO_SD_CD,
156         .wp_gpio = -1,
157         .power_gpio = -1,
158         .tap_delay = 0x3,
159         .trim_delay = 0x3,
160         .ddr_clk_limit = 41000000,
161 };
162
163 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
164         .cd_gpio = -1,
165         .wp_gpio = -1,
166         .power_gpio = -1,
167         .is_8bit = 1,
168         .tap_delay = 0x5,
169         .trim_delay = 0x3,
170         .ddr_clk_limit = 41000000,
171         .mmc_data = {
172                 .built_in = 1,
173                 .ocr_mask = MMC_OCR_1V8_MASK,
174         }
175 };
176
177 static struct platform_device tegra_sdhci_device0 = {
178         .name           = "sdhci-tegra",
179         .id             = 0,
180         .resource       = sdhci_resource0,
181         .num_resources  = ARRAY_SIZE(sdhci_resource0),
182         .dev = {
183                 .platform_data = &tegra_sdhci_platform_data0,
184         },
185 };
186
187 static struct platform_device tegra_sdhci_device2 = {
188         .name           = "sdhci-tegra",
189         .id             = 2,
190         .resource       = sdhci_resource2,
191         .num_resources  = ARRAY_SIZE(sdhci_resource2),
192         .dev = {
193                 .platform_data = &tegra_sdhci_platform_data2,
194         },
195 };
196
197 static struct platform_device tegra_sdhci_device3 = {
198         .name           = "sdhci-tegra",
199         .id             = 3,
200         .resource       = sdhci_resource3,
201         .num_resources  = ARRAY_SIZE(sdhci_resource3),
202         .dev = {
203                 .platform_data = &tegra_sdhci_platform_data3,
204         },
205 };
206
207 static int pismo_wifi_status_register(
208                 void (*callback)(int card_present, void *dev_id),
209                 void *dev_id)
210 {
211         if (wifi_status_cb)
212                 return -EAGAIN;
213         wifi_status_cb = callback;
214         wifi_status_cb_devid = dev_id;
215         return 0;
216 }
217
218 static int pismo_wifi_set_carddetect(int val)
219 {
220         pr_debug("%s: %d\n", __func__, val);
221         if (wifi_status_cb)
222                 wifi_status_cb(val, wifi_status_cb_devid);
223         else
224                 pr_warning("%s: Nobody to notify\n", __func__);
225         return 0;
226 }
227
228 static struct regulator *pismo_vdd_com_3v3;
229 static struct regulator *pismo_vddio_com_1v8;
230 #define PISMO_VDD_WIFI_3V3 "avdd"
231 #define PISMO_VDD_WIFI_1V8 "dvdd"
232
233 static int pismo_wifi_regulator_enable(void)
234 {
235         int ret = 0;
236
237         /* Enable COM's vdd_com_3v3 regulator*/
238         if (IS_ERR_OR_NULL(pismo_vdd_com_3v3)) {
239                 pismo_vdd_com_3v3 = regulator_get(&pismo_wifi_device.dev,
240                                                         PISMO_VDD_WIFI_3V3);
241                 if (IS_ERR(pismo_vdd_com_3v3)) {
242                         pr_err("Couldn't get regulator "
243                                 PISMO_VDD_WIFI_3V3 "\n");
244                         return PTR_ERR(pismo_vdd_com_3v3);
245                 }
246
247                 ret = regulator_enable(pismo_vdd_com_3v3);
248                 if (ret < 0) {
249                         pr_err("Couldn't enable regulator "
250                                 PISMO_VDD_WIFI_3V3 "\n");
251                         regulator_put(pismo_vdd_com_3v3);
252                         pismo_vdd_com_3v3 = NULL;
253                         return ret;
254                 }
255         }
256
257         /* Enable COM's vddio_com_1v8 regulator*/
258         if (IS_ERR_OR_NULL(pismo_vddio_com_1v8)) {
259                 pismo_vddio_com_1v8 = regulator_get(&pismo_wifi_device.dev,
260                         PISMO_VDD_WIFI_1V8);
261                 if (IS_ERR(pismo_vddio_com_1v8)) {
262                         pr_err("Couldn't get regulator "
263                                 PISMO_VDD_WIFI_1V8 "\n");
264                         regulator_disable(pismo_vdd_com_3v3);
265
266                         regulator_put(pismo_vdd_com_3v3);
267                         pismo_vdd_com_3v3 = NULL;
268                         return PTR_ERR(pismo_vddio_com_1v8);
269                 }
270
271                 ret = regulator_enable(pismo_vddio_com_1v8);
272                 if (ret < 0) {
273                         pr_err("Couldn't enable regulator "
274                                 PISMO_VDD_WIFI_1V8 "\n");
275                         regulator_put(pismo_vddio_com_1v8);
276                         pismo_vddio_com_1v8 = NULL;
277
278                         regulator_disable(pismo_vdd_com_3v3);
279                         regulator_put(pismo_vdd_com_3v3);
280                         pismo_vdd_com_3v3 = NULL;
281                         return ret;
282                 }
283         }
284
285         return ret;
286 }
287
288 static void pismo_wifi_regulator_disable(void)
289 {
290         /* Disable COM's vdd_com_3v3 regulator*/
291         if (!IS_ERR_OR_NULL(pismo_vdd_com_3v3)) {
292                 regulator_disable(pismo_vdd_com_3v3);
293                 regulator_put(pismo_vdd_com_3v3);
294                 pismo_vdd_com_3v3 = NULL;
295         }
296
297         /* Disable COM's vddio_com_1v8 regulator*/
298         if (!IS_ERR_OR_NULL(pismo_vddio_com_1v8)) {
299                 regulator_disable(pismo_vddio_com_1v8);
300                 regulator_put(pismo_vddio_com_1v8);
301                 pismo_vddio_com_1v8 = NULL;
302         }
303 }
304
305 static int pismo_wifi_power(int on)
306 {
307         struct tegra_io_dpd *sd_dpd;
308         int ret = 0;
309
310         pr_debug("%s: %d\n", __func__, on);
311         /* Enable COM's regulators on wi-fi poer on*/
312         if (on == 1) {
313                 ret = pismo_wifi_regulator_enable();
314                 if (ret < 0) {
315                         pr_err("Failed to enable COM regulators\n");
316                         return ret;
317                 }
318         }
319
320         /*
321          * FIXME : we need to revisit IO DPD code
322          * on how should multiple pins under DPD get controlled
323          *
324          * pismo GPIO WLAN enable is part of SDMMC3 pin group
325          */
326         sd_dpd = tegra_io_dpd_get(&tegra_sdhci_device2.dev);
327         if (sd_dpd) {
328                 mutex_lock(&sd_dpd->delay_lock);
329                 tegra_io_dpd_disable(sd_dpd);
330                 mutex_unlock(&sd_dpd->delay_lock);
331         }
332         gpio_set_value(PISMO_WLAN_PWR, on);
333         mdelay(100);
334         gpio_set_value(PISMO_WLAN_RST, on);
335         mdelay(200);
336         if (sd_dpd) {
337                 mutex_lock(&sd_dpd->delay_lock);
338                 tegra_io_dpd_enable(sd_dpd);
339                 mutex_unlock(&sd_dpd->delay_lock);
340         }
341
342         /* Disable COM's regulators on wi-fi poer off*/
343         if (on != 1) {
344                 pr_debug("Disabling COM regulators\n");
345                 pismo_wifi_regulator_disable();
346         }
347
348         return ret;
349 }
350
351 static int pismo_wifi_reset(int on)
352 {
353         pr_debug("%s: do nothing\n", __func__);
354         return 0;
355 }
356
357 static int __init pismo_wifi_init(void)
358 {
359         int rc;
360
361         rc = gpio_request(PISMO_WLAN_PWR, "wlan_power");
362         if (rc)
363                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
364         rc = gpio_request(PISMO_WLAN_RST, "wlan_rst");
365         if (rc)
366                 pr_err("WLAN_RST gpio request failed:%d\n", rc);
367         rc = gpio_request(PISMO_WLAN_WOW, "bcmsdh_sdmmc");
368         if (rc)
369                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
370
371         rc = gpio_direction_output(PISMO_WLAN_PWR, 0);
372         if (rc)
373                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
374         gpio_direction_output(PISMO_WLAN_RST, 0);
375         if (rc)
376                 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
377         rc = gpio_direction_input(PISMO_WLAN_WOW);
378         if (rc)
379                 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
380
381         wifi_resource[0].start = wifi_resource[0].end =
382                 gpio_to_irq(PISMO_WLAN_WOW);
383
384         platform_device_register(&pismo_wifi_device);
385         return 0;
386 }
387
388 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
389 static int __init pismo_wifi_prepower(void)
390 {
391         if (!machine_is_pismo())
392                 return 0;
393
394         pismo_wifi_power(1);
395
396         return 0;
397 }
398
399 subsys_initcall_sync(pismo_wifi_prepower);
400 #endif
401
402 int __init pismo_sdhci_init(void)
403 {
404         platform_device_register(&tegra_sdhci_device3);
405         platform_device_register(&tegra_sdhci_device2);
406         platform_device_register(&tegra_sdhci_device0);
407         pismo_wifi_init();
408         return 0;
409 }