arch: arm: ardbeg: interposer bringup
[linux-3.10.git] / arch / arm / mach-tegra / board-ardbeg-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-ardbeg-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-ardbeg.h"
38 #include "iomap.h"
39
40 #ifdef CONFIG_ARCH_TEGRA_11x_SOC
41 #define ARDBEG_WLAN_PWR TEGRA_GPIO_PCC5
42 #define ARDBEG_WLAN_WOW TEGRA_GPIO_PU5
43 #else
44 /* FIXME: update GPIO's for 124 */
45 #define ARDBEG_WLAN_PWR  TEGRA_GPIO_PL7
46 #define ARDBEG_WLAN_WOW  TEGRA_GPIO_PO2
47 #endif
48
49 #define ARDBEG_SD_CD    (MAX77660_GPIO_BASE + MAX77660_GPIO9)
50
51 static void (*wifi_status_cb)(int card_present, void *dev_id);
52 static void *wifi_status_cb_devid;
53 static int ardbeg_wifi_status_register(void (*callback)(int , void *), void *);
54
55 static int ardbeg_wifi_reset(int on);
56 static int ardbeg_wifi_power(int on);
57 static int ardbeg_wifi_set_carddetect(int val);
58
59 static struct wifi_platform_data ardbeg_wifi_control = {
60         .set_power      = ardbeg_wifi_power,
61         .set_reset      = ardbeg_wifi_reset,
62         .set_carddetect = ardbeg_wifi_set_carddetect,
63 };
64
65 static struct resource wifi_resource[] = {
66         [0] = {
67                 .name   = "bcm4329_wlan_irq",
68                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
69                                 | IORESOURCE_IRQ_SHAREABLE,
70         },
71 };
72
73 static struct platform_device ardbeg_wifi_device = {
74         .name           = "bcm4329_wlan",
75         .id             = 1,
76         .num_resources  = 1,
77         .resource       = wifi_resource,
78         .dev            = {
79                 .platform_data = &ardbeg_wifi_control,
80         },
81 };
82
83 static struct resource sdhci_resource0[] = {
84         [0] = {
85                 .start  = INT_SDMMC1,
86                 .end    = INT_SDMMC1,
87                 .flags  = IORESOURCE_IRQ,
88         },
89         [1] = {
90                 .start  = TEGRA_SDMMC1_BASE,
91                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
92                 .flags  = IORESOURCE_MEM,
93         },
94 };
95
96 static struct resource sdhci_resource2[] = {
97         [0] = {
98                 .start  = INT_SDMMC3,
99                 .end    = INT_SDMMC3,
100                 .flags  = IORESOURCE_IRQ,
101         },
102         [1] = {
103                 .start  = TEGRA_SDMMC3_BASE,
104                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
105                 .flags  = IORESOURCE_MEM,
106         },
107 };
108
109 static struct resource sdhci_resource3[] = {
110         [0] = {
111                 .start  = INT_SDMMC4,
112                 .end    = INT_SDMMC4,
113                 .flags  = IORESOURCE_IRQ,
114         },
115         [1] = {
116                 .start  = TEGRA_SDMMC4_BASE,
117                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
118                 .flags  = IORESOURCE_MEM,
119         },
120 };
121
122 #ifdef CONFIG_MMC_EMBEDDED_SDIO
123 static struct embedded_sdio_data embedded_sdio_data0 = {
124         .cccr   = {
125                 .sdio_vsn       = 2,
126                 .multi_block    = 1,
127                 .low_speed      = 0,
128                 .wide_bus       = 0,
129                 .high_power     = 1,
130                 .high_speed     = 1,
131         },
132         .cis  = {
133                 .vendor  = 0x02d0,
134                 .device  = 0x4329,
135         },
136 };
137 #endif
138
139 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
140         .mmc_data = {
141                 .register_status_notify = ardbeg_wifi_status_register,
142 #ifdef CONFIG_MMC_EMBEDDED_SDIO
143                 .embedded_sdio = &embedded_sdio_data0,
144 #endif
145                 .built_in = 0,
146                 .ocr_mask = MMC_OCR_1V8_MASK,
147         },
148 #ifndef CONFIG_MMC_EMBEDDED_SDIO
149         .pm_flags = MMC_PM_KEEP_POWER,
150 #endif
151         .cd_gpio = -1,
152         .wp_gpio = -1,
153         .power_gpio = -1,
154         .tap_delay = 0x3,
155         .trim_delay = 0xA,
156         .ddr_clk_limit = 41000000,
157         /* FIXME remove uhs_mask for T148 silicon */
158         .uhs_mask = MMC_UHS_MASK_SDR104 |
159                 MMC_UHS_MASK_DDR50,
160 };
161
162 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
163         .cd_gpio = -1,
164         .wp_gpio = -1,
165         .power_gpio = -1,
166 /*      .max_clk = 12000000, */
167 };
168
169 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
170         .cd_gpio = -1,
171         .wp_gpio = -1,
172         .power_gpio = -1,
173         .is_8bit = 1,
174         .mmc_data = {
175                 .built_in = 1,
176                 .ocr_mask = MMC_OCR_1V8_MASK,
177         }
178 /*      .max_clk = 12000000, */
179 };
180
181 static struct platform_device tegra_sdhci_device0 = {
182         .name           = "sdhci-tegra",
183         .id             = 0,
184         .resource       = sdhci_resource0,
185         .num_resources  = ARRAY_SIZE(sdhci_resource0),
186         .dev = {
187                 .platform_data = &tegra_sdhci_platform_data0,
188         },
189 };
190
191 static struct platform_device tegra_sdhci_device2 = {
192         .name           = "sdhci-tegra",
193         .id             = 2,
194         .resource       = sdhci_resource2,
195         .num_resources  = ARRAY_SIZE(sdhci_resource2),
196         .dev = {
197                 .platform_data = &tegra_sdhci_platform_data2,
198         },
199 };
200
201 static struct platform_device tegra_sdhci_device3 = {
202         .name           = "sdhci-tegra",
203         .id             = 3,
204         .resource       = sdhci_resource3,
205         .num_resources  = ARRAY_SIZE(sdhci_resource3),
206         .dev = {
207                 .platform_data = &tegra_sdhci_platform_data3,
208         },
209 };
210
211 static int ardbeg_wifi_status_register(
212                 void (*callback)(int card_present, void *dev_id),
213                 void *dev_id)
214 {
215         if (wifi_status_cb)
216                 return -EAGAIN;
217         wifi_status_cb = callback;
218         wifi_status_cb_devid = dev_id;
219         return 0;
220 }
221
222 static int ardbeg_wifi_set_carddetect(int val)
223 {
224         pr_debug("%s: %d\n", __func__, val);
225         if (wifi_status_cb)
226                 wifi_status_cb(val, wifi_status_cb_devid);
227         else
228                 pr_warn("%s: Nobody to notify\n", __func__);
229         return 0;
230 }
231
232 static int ardbeg_wifi_power(int on)
233 {
234         pr_err("%s: %d\n", __func__, on);
235
236         gpio_set_value(ARDBEG_WLAN_PWR, on);
237         mdelay(100);
238
239         return 0;
240 }
241
242 static int ardbeg_wifi_reset(int on)
243 {
244         pr_debug("%s: do nothing\n", __func__);
245         return 0;
246 }
247
248 static int __init ardbeg_wifi_init(void)
249 {
250         int rc;
251
252         rc = gpio_request(ARDBEG_WLAN_PWR, "wlan_power");
253         if (rc)
254                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
255         rc = gpio_request(ARDBEG_WLAN_WOW, "bcmsdh_sdmmc");
256         if (rc)
257                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
258
259         rc = gpio_direction_output(ARDBEG_WLAN_PWR, 0);
260         if (rc)
261                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
262         rc = gpio_direction_input(ARDBEG_WLAN_WOW);
263         if (rc)
264                 pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
265
266         wifi_resource[0].start = wifi_resource[0].end =
267                 gpio_to_irq(ARDBEG_WLAN_WOW);
268
269         platform_device_register(&ardbeg_wifi_device);
270         return 0;
271 }
272
273 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
274 static int __init ardbeg_wifi_prepower(void)
275 {
276         if (!of_machine_is_compatible("nvidia,ardbeg"))
277                 return 0;
278         ardbeg_wifi_power(1);
279
280         return 0;
281 }
282
283 subsys_initcall_sync(ardbeg_wifi_prepower);
284 #endif
285
286 int __init ardbeg_sdhci_init(void)
287 {
288         /* FIXME: Disabled SDMMC1 and WiFi */
289 #ifndef CONFIG_USE_OF
290         platform_device_register(&tegra_sdhci_device3);
291         platform_device_register(&tegra_sdhci_device2);
292 #endif
293         return 0;
294 }