ARM: tegra: dalmore: sdhci platform registration
[linux-3.10.git] / arch / arm / mach-tegra / board-dalmore-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-dalmore-sdhci.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  * Copyright (c) 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
18 #include <linux/resource.h>
19 #include <linux/platform_device.h>
20 #include <linux/wlan_plat.h>
21 #include <linux/delay.h>
22 #include <linux/gpio.h>
23 #include <linux/clk.h>
24 #include <linux/err.h>
25 #include <linux/regulator/consumer.h>
26 #include <linux/mmc/host.h>
27 #include <linux/wl12xx.h>
28 #include <linux/platform_data/mmc-sdhci-tegra.h>
29
30 #include <asm/mach-types.h>
31 #include <mach/irqs.h>
32 #include <mach/gpio-tegra.h>
33
34 #include "tegra-board-id.h"
35 #include "gpio-names.h"
36 #include "board.h"
37 #include "board-dalmore.h"
38 #include "dvfs.h"
39 #include "iomap.h"
40
41 #define DALMORE_WLAN_PWR        TEGRA_GPIO_PCC5
42 #define DALMORE_WLAN_RST        TEGRA_GPIO_PX7
43 #define DALMORE_WLAN_WOW        TEGRA_GPIO_PU5
44 #define DALMORE_SD_CD           TEGRA_GPIO_PV2
45 #define DALMORE_SD_WP           TEGRA_GPIO_PQ4
46 static void (*wifi_status_cb)(int card_present, void *dev_id);
47 static void *wifi_status_cb_devid;
48 static int dalmore_wifi_status_register(void (*callback)(int , void *), void *);
49
50 static int dalmore_wifi_reset(int on);
51 static int dalmore_wifi_power(int on);
52 static int dalmore_wifi_set_carddetect(int val);
53
54 static 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
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 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
78 #ifdef CONFIG_MMC_EMBEDDED_SDIO
79 static struct embedded_sdio_data embedded_sdio_data0 = {
80         .cccr   = {
81                 .sdio_vsn       = 2,
82                 .multi_block    = 1,
83                 .low_speed      = 0,
84                 .wide_bus       = 0,
85                 .high_power     = 1,
86                 .high_speed     = 1,
87         },
88         .cis  = {
89                 .vendor  = 0x02d0,
90                 .device  = 0x4329,
91         },
92 };
93 #endif
94
95 struct tegra_sdhci_platform_data dalmore_tegra_sdhci_platform_data0 = {
96         .mmc_data = {
97                 .register_status_notify = dalmore_wifi_status_register,
98 #ifdef CONFIG_MMC_EMBEDDED_SDIO
99                 .embedded_sdio = &embedded_sdio_data0,
100 #endif
101                 .built_in = 0,
102                 .ocr_mask = MMC_OCR_1V8_MASK,
103         },
104 #ifndef CONFIG_MMC_EMBEDDED_SDIO
105         .pm_flags = MMC_PM_KEEP_POWER,
106 #endif
107         .cd_gpio = -1,
108         .wp_gpio = -1,
109         .power_gpio = -1,
110         .tap_delay = 0x2,
111         .trim_delay = 0x2,
112         .ddr_clk_limit = 41000000,
113         .max_clk_limit = 82000000,
114         .uhs_mask = MMC_UHS_MASK_DDR50,
115 };
116
117 static struct resource sdhci_resource0[] = {
118         [0] = {
119                 .start  = INT_SDMMC1,
120                 .end    = INT_SDMMC1,
121                 .flags  = IORESOURCE_IRQ,
122         },
123         [1] = {
124                 .start  = TEGRA_SDMMC1_BASE,
125                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
126                 .flags  = IORESOURCE_MEM,
127         },
128 };
129
130 static struct resource sdhci_resource2[] = {
131         [0] = {
132                 .start  = INT_SDMMC3,
133                 .end    = INT_SDMMC3,
134                 .flags  = IORESOURCE_IRQ,
135         },
136         [1] = {
137                 .start  = TEGRA_SDMMC3_BASE,
138                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
139                 .flags  = IORESOURCE_MEM,
140         },
141 };
142
143 static struct resource sdhci_resource3[] = {
144         [0] = {
145                 .start  = INT_SDMMC4,
146                 .end    = INT_SDMMC4,
147                 .flags  = IORESOURCE_IRQ,
148         },
149         [1] = {
150                 .start  = TEGRA_SDMMC4_BASE,
151                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
152                 .flags  = IORESOURCE_MEM,
153         },
154 };
155
156 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
157         .cd_gpio = DALMORE_SD_CD,
158         .wp_gpio = DALMORE_SD_WP,
159         .power_gpio = -1,
160         .tap_delay = 0x3,
161         .trim_delay = 0x3,
162         .ddr_clk_limit = 41000000,
163         .max_clk_limit = 82000000,
164         .uhs_mask = MMC_UHS_MASK_DDR50,
165         .power_off_rail = true,
166 };
167
168 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
169         .cd_gpio = -1,
170         .wp_gpio = -1,
171         .power_gpio = -1,
172         .is_8bit = 1,
173         .tap_delay = 0x5,
174         .trim_delay = 0xA,
175         .ddr_trim_delay = -1,
176         .ddr_clk_limit = 41000000,
177         .max_clk_limit = 156000000,
178         .mmc_data = {
179                 .built_in = 1,
180                 .ocr_mask = MMC_OCR_1V8_MASK,
181         }
182 };
183
184 static struct platform_device tegra_sdhci_device0 = {
185         .name           = "sdhci-tegra",
186         .id             = 0,
187         .resource       = sdhci_resource0,
188         .num_resources  = ARRAY_SIZE(sdhci_resource0),
189         .dev = {
190                 .platform_data = &dalmore_tegra_sdhci_platform_data0,
191         },
192 };
193
194 static struct platform_device tegra_sdhci_device2 = {
195         .name           = "sdhci-tegra",
196         .id             = 2,
197         .resource       = sdhci_resource2,
198         .num_resources  = ARRAY_SIZE(sdhci_resource2),
199         .dev = {
200                 .platform_data = &tegra_sdhci_platform_data2,
201         },
202 };
203
204 static struct platform_device tegra_sdhci_device3 = {
205         .name           = "sdhci-tegra",
206         .id             = 3,
207         .resource       = sdhci_resource3,
208         .num_resources  = ARRAY_SIZE(sdhci_resource3),
209         .dev = {
210                 .platform_data = &tegra_sdhci_platform_data3,
211         },
212 };
213
214 static int dalmore_wifi_status_register(
215                 void (*callback)(int card_present, void *dev_id),
216                 void *dev_id)
217 {
218         if (wifi_status_cb)
219                 return -EAGAIN;
220         wifi_status_cb = callback;
221         wifi_status_cb_devid = dev_id;
222         return 0;
223 }
224
225 static int dalmore_wifi_set_carddetect(int val)
226 {
227         pr_debug("%s: %d\n", __func__, val);
228         if (wifi_status_cb)
229                 wifi_status_cb(val, wifi_status_cb_devid);
230         else
231                 pr_warning("%s: Nobody to notify\n", __func__);
232         return 0;
233 }
234
235 static struct regulator *dalmore_vdd_com_3v3;
236 static struct regulator *dalmore_vddio_com_1v8;
237 #define DALMORE_VDD_WIFI_3V3 "avdd"
238 #define DALMORE_VDD_WIFI_1V8 "dvdd"
239
240 static int dalmore_wifi_regulator_enable(void)
241 {
242         int ret = 0;
243
244         /* Enable COM's vdd_com_3v3 regulator*/
245         if (IS_ERR_OR_NULL(dalmore_vdd_com_3v3)) {
246                 dalmore_vdd_com_3v3 = regulator_get(&dalmore_wifi_device.dev,
247                                                         DALMORE_VDD_WIFI_3V3);
248                 if (IS_ERR_OR_NULL(dalmore_vdd_com_3v3)) {
249                         pr_err("Couldn't get regulator "
250                                 DALMORE_VDD_WIFI_3V3 "\n");
251                         return PTR_ERR(dalmore_vdd_com_3v3);
252                 }
253
254                 ret = regulator_enable(dalmore_vdd_com_3v3);
255                 if (ret < 0) {
256                         pr_err("Couldn't enable regulator "
257                                 DALMORE_VDD_WIFI_3V3 "\n");
258                         regulator_put(dalmore_vdd_com_3v3);
259                         dalmore_vdd_com_3v3 = NULL;
260                         return ret;
261                 }
262         }
263
264         /* Enable COM's vddio_com_1v8 regulator*/
265         if (IS_ERR_OR_NULL(dalmore_vddio_com_1v8)) {
266                 dalmore_vddio_com_1v8 = regulator_get(&dalmore_wifi_device.dev,
267                         DALMORE_VDD_WIFI_1V8);
268                 if (IS_ERR_OR_NULL(dalmore_vddio_com_1v8)) {
269                         pr_err("Couldn't get regulator "
270                                 DALMORE_VDD_WIFI_1V8 "\n");
271                         regulator_disable(dalmore_vdd_com_3v3);
272
273                         regulator_put(dalmore_vdd_com_3v3);
274                         dalmore_vdd_com_3v3 = NULL;
275                         return PTR_ERR(dalmore_vddio_com_1v8);
276                 }
277
278                 ret = regulator_enable(dalmore_vddio_com_1v8);
279                 if (ret < 0) {
280                         pr_err("Couldn't enable regulator "
281                                 DALMORE_VDD_WIFI_1V8 "\n");
282                         regulator_put(dalmore_vddio_com_1v8);
283                         dalmore_vddio_com_1v8 = NULL;
284
285                         regulator_disable(dalmore_vdd_com_3v3);
286                         regulator_put(dalmore_vdd_com_3v3);
287                         dalmore_vdd_com_3v3 = NULL;
288                         return ret;
289                 }
290         }
291
292         return ret;
293 }
294
295 static void dalmore_wifi_regulator_disable(void)
296 {
297         /* Disable COM's vdd_com_3v3 regulator*/
298         if (!IS_ERR_OR_NULL(dalmore_vdd_com_3v3)) {
299                 regulator_disable(dalmore_vdd_com_3v3);
300                 regulator_put(dalmore_vdd_com_3v3);
301                 dalmore_vdd_com_3v3 = NULL;
302         }
303
304         /* Disable COM's vddio_com_1v8 regulator*/
305         if (!IS_ERR_OR_NULL(dalmore_vddio_com_1v8)) {
306                 regulator_disable(dalmore_vddio_com_1v8);
307                 regulator_put(dalmore_vddio_com_1v8);
308                 dalmore_vddio_com_1v8 = NULL;
309         }
310 }
311
312 static int dalmore_wifi_power(int on)
313 {
314         int ret = 0;
315
316         pr_debug("%s: %d\n", __func__, on);
317         /* Enable COM's regulators on wi-fi poer on*/
318         if (on == 1) {
319                 ret = dalmore_wifi_regulator_enable();
320                 if (ret < 0) {
321                         pr_err("Failed to enable COM regulators\n");
322                         return ret;
323                 }
324         }
325
326         gpio_set_value(DALMORE_WLAN_PWR, on);
327         mdelay(100);
328         gpio_set_value(DALMORE_WLAN_RST, on);
329         mdelay(200);
330
331         /* Disable COM's regulators on wi-fi poer off*/
332         if (on != 1) {
333                 pr_debug("Disabling COM regulators\n");
334                 dalmore_wifi_regulator_disable();
335         }
336
337         return ret;
338 }
339
340 static int dalmore_wifi_reset(int on)
341 {
342         pr_debug("%s: do nothing\n", __func__);
343         return 0;
344 }
345
346 static int __init dalmore_wifi_init(void)
347 {
348         int rc;
349
350         rc = gpio_request(DALMORE_WLAN_PWR, "wlan_power");
351         if (rc)
352                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
353         rc = gpio_request(DALMORE_WLAN_RST, "wlan_rst");
354         if (rc)
355                 pr_err("WLAN_RST gpio request failed:%d\n", rc);
356         rc = gpio_request(DALMORE_WLAN_WOW, "bcmsdh_sdmmc");
357         if (rc)
358                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
359
360         rc = gpio_direction_output(DALMORE_WLAN_PWR, 0);
361         if (rc)
362                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
363         gpio_direction_output(DALMORE_WLAN_RST, 0);
364         if (rc)
365                 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
366         rc = gpio_direction_input(DALMORE_WLAN_WOW);
367         if (rc)
368                 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
369
370         wifi_resource[0].start = wifi_resource[0].end =
371                 gpio_to_irq(DALMORE_WLAN_WOW);
372
373         platform_device_register(&dalmore_wifi_device);
374         return 0;
375 }
376
377 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
378 static int __init dalmore_wifi_prepower(void)
379 {
380         if (!machine_is_dalmore())
381                 return 0;
382
383         dalmore_wifi_power(1);
384
385         return 0;
386 }
387
388 subsys_initcall_sync(dalmore_wifi_prepower);
389 #endif
390
391 int __init dalmore_sdhci_init(void)
392 {
393         int nominal_core_mv;
394         int min_vcore_override_mv;
395         struct board_info board_info;
396
397         nominal_core_mv =
398                 tegra_dvfs_rail_get_nominal_millivolts(tegra_core_rail);
399         if (nominal_core_mv) {
400                 dalmore_tegra_sdhci_platform_data0.nominal_vcore_mv =
401                         nominal_core_mv;
402                 tegra_sdhci_platform_data2.nominal_vcore_mv = nominal_core_mv;
403                 tegra_sdhci_platform_data3.nominal_vcore_mv = nominal_core_mv;
404         }
405         min_vcore_override_mv =
406                 tegra_dvfs_rail_get_override_floor(tegra_core_rail);
407         if (min_vcore_override_mv) {
408                 dalmore_tegra_sdhci_platform_data0.min_vcore_override_mv =
409                         min_vcore_override_mv;
410                 tegra_sdhci_platform_data2.min_vcore_override_mv =
411                         min_vcore_override_mv;
412                 tegra_sdhci_platform_data3.min_vcore_override_mv =
413                         min_vcore_override_mv;
414         }
415         if ((tegra_sdhci_platform_data3.uhs_mask & MMC_MASK_HS200)
416                 && (!(tegra_sdhci_platform_data3.uhs_mask &
417                 MMC_UHS_MASK_DDR50)))
418                 tegra_sdhci_platform_data3.trim_delay = 0;
419         tegra_get_board_info(&board_info);
420         if (board_info.fab == BOARD_FAB_A05) {
421                 tegra_sdhci_platform_data2.wp_gpio = -1;
422                 dalmore_tegra_sdhci_platform_data0.max_clk_limit = 156000000;
423                 tegra_sdhci_platform_data2.max_clk_limit = 156000000;
424         }
425         platform_device_register(&tegra_sdhci_device3);
426         platform_device_register(&tegra_sdhci_device2);
427         platform_device_register(&tegra_sdhci_device0);
428         dalmore_wifi_init();
429         return 0;
430 }