ARM: tegra: sdhci: Pass speedo id in platform data
[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 #include <linux/tegra-fuse.h>
31
32 #include <asm/mach-types.h>
33 #include <mach/irqs.h>
34 #include <mach/gpio-tegra.h>
35
36 #include "gpio-names.h"
37 #include "board.h"
38 #include "board-ardbeg.h"
39 #include "dvfs.h"
40 #include "iomap.h"
41 #include "tegra-board-id.h"
42
43 #define ARDBEG_WLAN_RST TEGRA_GPIO_PCC5
44 #define ARDBEG_WLAN_PWR TEGRA_GPIO_PX7
45 #define ARDBEG_WLAN_WOW TEGRA_GPIO_PU5
46 #if defined(CONFIG_BCMDHD_EDP_SUPPORT)
47 #define ON 3070 /* 3069mW */
48 #define OFF 0
49 static unsigned int wifi_states[] = {ON, OFF};
50 #endif
51
52 #define ARDBEG_SD_CD    TEGRA_GPIO_PV2
53 #define ARDBEG_SD_WP    TEGRA_GPIO_PQ4
54 #define FUSE_SOC_SPEEDO_0       0x134
55
56 static void (*wifi_status_cb)(int card_present, void *dev_id);
57 static void *wifi_status_cb_devid;
58 static int ardbeg_wifi_status_register(void (*callback)(int , void *), void *);
59
60 static int ardbeg_wifi_reset(int on);
61 static int ardbeg_wifi_power(int on);
62 static int ardbeg_wifi_set_carddetect(int val);
63 static int ardbeg_wifi_get_mac_addr(unsigned char *buf);
64
65 static struct wifi_platform_data ardbeg_wifi_control = {
66         .set_power      = ardbeg_wifi_power,
67         .set_reset      = ardbeg_wifi_reset,
68         .set_carddetect = ardbeg_wifi_set_carddetect,
69         .get_mac_addr   = ardbeg_wifi_get_mac_addr,
70 #if defined (CONFIG_BCMDHD_EDP_SUPPORT)
71         /* wifi edp client information */
72         .client_info    = {
73                 .name           = "wifi_edp_client",
74                 .states         = wifi_states,
75                 .num_states     = ARRAY_SIZE(wifi_states),
76                 .e0_index       = 0,
77                 .priority       = EDP_MAX_PRIO,
78         },
79 #endif
80 };
81
82 static struct resource wifi_resource[] = {
83         [0] = {
84                 .name   = "bcm4329_wlan_irq",
85                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
86                                 | IORESOURCE_IRQ_SHAREABLE,
87         },
88 };
89
90 static struct platform_device ardbeg_wifi_device = {
91         .name           = "bcm4329_wlan",
92         .id             = 1,
93         .num_resources  = 1,
94         .resource       = wifi_resource,
95         .dev            = {
96                 .platform_data = &ardbeg_wifi_control,
97         },
98 };
99
100 static struct resource mrvl_wifi_resource[] = {
101         [0] = {
102                 .name   = "mrvl_wlan_irq",
103                 .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE,
104         },
105 };
106
107 static struct platform_device marvell_wifi_device = {
108         .name           = "mrvl_wlan",
109         .id             = 1,
110         .num_resources  = 1,
111         .resource       = mrvl_wifi_resource,
112         .dev            = {
113                 .platform_data = &ardbeg_wifi_control,
114         },
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 #ifdef CONFIG_MMC_EMBEDDED_SDIO
157 static struct embedded_sdio_data embedded_sdio_data0 = {
158         .cccr   = {
159                 .sdio_vsn       = 2,
160                 .multi_block    = 1,
161                 .low_speed      = 0,
162                 .wide_bus       = 0,
163                 .high_power     = 1,
164                 .high_speed     = 1,
165         },
166         .cis  = {
167                 .vendor  = 0x02d0,
168                 .device  = 0x4329,
169         },
170 };
171 #endif
172
173 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
174         .mmc_data = {
175                 .register_status_notify = ardbeg_wifi_status_register,
176 #ifdef CONFIG_MMC_EMBEDDED_SDIO
177                 .embedded_sdio = &embedded_sdio_data0,
178 #endif
179                 .built_in = 0,
180                 .ocr_mask = MMC_OCR_1V8_MASK,
181         },
182         .cd_gpio = -1,
183         .wp_gpio = -1,
184         .power_gpio = -1,
185         .tap_delay = 0,
186         .trim_delay = 0x2,
187         .ddr_clk_limit = 41000000,
188         .uhs_mask = MMC_UHS_MASK_DDR50 |
189                 MMC_UHS_MASK_SDR50,
190         .calib_3v3_offsets = 0x7676,
191         .calib_1v8_offsets = 0x7676,
192 };
193
194 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
195         .cd_gpio = ARDBEG_SD_CD,
196         .wp_gpio = -1,
197         .power_gpio = -1,
198         .tap_delay = 0,
199         .trim_delay = 0x3,
200         .uhs_mask = MMC_UHS_MASK_DDR50,
201         .calib_3v3_offsets = 0x7676,
202         .calib_1v8_offsets = 0x7676,
203 };
204
205 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
206         .cd_gpio = -1,
207         .wp_gpio = -1,
208         .power_gpio = -1,
209         .is_8bit = 1,
210         .tap_delay = 0x4,
211         .trim_delay = 0x3,
212         .ddr_trim_delay = 0x0,
213         .mmc_data = {
214                 .built_in = 1,
215                 .ocr_mask = MMC_OCR_1V8_MASK,
216         },
217         .ddr_clk_limit = 51000000,
218         .max_clk_limit = 102000000,
219         .calib_3v3_offsets = 0x0202,
220         .calib_1v8_offsets = 0x0202,
221 };
222
223 static struct platform_device tegra_sdhci_device0 = {
224         .name           = "sdhci-tegra",
225         .id             = 0,
226         .resource       = sdhci_resource0,
227         .num_resources  = ARRAY_SIZE(sdhci_resource0),
228         .dev = {
229                 .platform_data = &tegra_sdhci_platform_data0,
230         },
231 };
232
233 static struct platform_device tegra_sdhci_device2 = {
234         .name           = "sdhci-tegra",
235         .id             = 2,
236         .resource       = sdhci_resource2,
237         .num_resources  = ARRAY_SIZE(sdhci_resource2),
238         .dev = {
239                 .platform_data = &tegra_sdhci_platform_data2,
240         },
241 };
242
243 static struct platform_device tegra_sdhci_device3 = {
244         .name           = "sdhci-tegra",
245         .id             = 3,
246         .resource       = sdhci_resource3,
247         .num_resources  = ARRAY_SIZE(sdhci_resource3),
248         .dev = {
249                 .platform_data = &tegra_sdhci_platform_data3,
250         },
251 };
252
253 static int ardbeg_wifi_status_register(
254                 void (*callback)(int card_present, void *dev_id),
255                 void *dev_id)
256 {
257         if (wifi_status_cb)
258                 return -EAGAIN;
259         wifi_status_cb = callback;
260         wifi_status_cb_devid = dev_id;
261         return 0;
262 }
263
264 static int ardbeg_wifi_set_carddetect(int val)
265 {
266         pr_debug("%s: %d\n", __func__, val);
267         if (wifi_status_cb)
268                 wifi_status_cb(val, wifi_status_cb_devid);
269         else
270                 pr_warn("%s: Nobody to notify\n", __func__);
271         return 0;
272 }
273
274 static int ardbeg_wifi_power(int on)
275 {
276         pr_err("%s: %d\n", __func__, on);
277
278         gpio_set_value(ARDBEG_WLAN_PWR, on);
279         gpio_set_value(ARDBEG_WLAN_RST, on);
280         mdelay(100);
281
282         return 0;
283 }
284
285 static int ardbeg_wifi_reset(int on)
286 {
287         pr_debug("%s: do nothing\n", __func__);
288         return 0;
289 }
290
291 #define ARDBEG_WIFI_MAC_ADDR_FILE       "/mnt/factory/wifi/wifi_mac.txt"
292
293 static int ardbeg_wifi_get_mac_addr(unsigned char *buf)
294 {
295         struct file *fp;
296         int rdlen;
297         char str[32];
298         int mac[6];
299         int ret = 0;
300
301         pr_debug("%s\n", __func__);
302
303         /* open wifi mac address file */
304         fp = filp_open(ARDBEG_WIFI_MAC_ADDR_FILE, O_RDONLY, 0);
305         if (IS_ERR(fp)) {
306                 pr_err("%s: cannot open %s\n",
307                         __func__, ARDBEG_WIFI_MAC_ADDR_FILE);
308                 return -ENOENT;
309         }
310
311         /* read wifi mac address file */
312         memset(str, 0, sizeof(str));
313         rdlen = kernel_read(fp, fp->f_pos, str, 17);
314         if (rdlen > 0)
315                 fp->f_pos += rdlen;
316         if (rdlen != 17) {
317                 pr_err("%s: bad mac address file"
318                         " - len %d < 17",
319                         __func__, rdlen);
320                 ret = -ENOENT;
321         } else if (sscanf(str, "%x:%x:%x:%x:%x:%x",
322                 &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
323                 pr_err("%s: bad mac address file"
324                         " - must contain xx:xx:xx:xx:xx:xx\n",
325                         __func__);
326                 ret = -ENOENT;
327         } else {
328                 pr_info("%s: using wifi mac %02x:%02x:%02x:%02x:%02x:%02x\n",
329                         __func__,
330                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
331                 buf[0] = (unsigned char) mac[0];
332                 buf[1] = (unsigned char) mac[1];
333                 buf[2] = (unsigned char) mac[2];
334                 buf[3] = (unsigned char) mac[3];
335                 buf[4] = (unsigned char) mac[4];
336                 buf[5] = (unsigned char) mac[5];
337         }
338
339         /* close wifi mac address file */
340         filp_close(fp, NULL);
341
342         return ret;
343 }
344
345 static int __init ardbeg_wifi_init(void)
346 {
347         int rc;
348
349         rc = gpio_request(ARDBEG_WLAN_PWR, "wlan_power");
350         if (rc)
351                 pr_err("WLAN_PWR gpio request failed:%d\n", rc);
352         rc = gpio_request(ARDBEG_WLAN_RST, "wlan_rst");
353         if (rc)
354                 pr_err("WLAN_RST gpio request failed:%d\n", rc);
355         rc = gpio_request(ARDBEG_WLAN_WOW, "bcmsdh_sdmmc");
356         if (rc)
357                 pr_err("WLAN_WOW gpio request failed:%d\n", rc);
358
359         rc = gpio_direction_output(ARDBEG_WLAN_PWR, 0);
360         if (rc)
361                 pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc);
362         rc = gpio_direction_output(ARDBEG_WLAN_RST, 0);
363         if (rc)
364                 pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc);
365
366         rc = gpio_direction_input(ARDBEG_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(ARDBEG_WLAN_WOW);
372
373         platform_device_register(&ardbeg_wifi_device);
374
375         mrvl_wifi_resource[0].start = mrvl_wifi_resource[0].end =
376                 gpio_to_irq(ARDBEG_WLAN_WOW);
377         platform_device_register(&marvell_wifi_device);
378
379         return 0;
380 }
381
382 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
383 static int __init ardbeg_wifi_prepower(void)
384 {
385         if (!of_machine_is_compatible("nvidia,ardbeg") &&
386                 !of_machine_is_compatible("nvidia,laguna") &&
387                 !of_machine_is_compatible("nvidia,ardbeg_sata") &&
388                 !of_machine_is_compatible("nvidia,tn8") &&
389                 !of_machine_is_compatible("nvidia,norrin") &&
390                 !of_machine_is_compatible("nvidia,jetson-tk1"))
391                 return 0;
392         ardbeg_wifi_power(1);
393
394         return 0;
395 }
396
397 subsys_initcall_sync(ardbeg_wifi_prepower);
398 #endif
399
400 int __init ardbeg_sdhci_init(void)
401 {
402         int nominal_core_mv;
403         int min_vcore_override_mv;
404         int boot_vcore_mv;
405         u32 speedo;
406         struct board_info board_info;
407
408         nominal_core_mv =
409                 tegra_dvfs_rail_get_nominal_millivolts(tegra_core_rail);
410         if (nominal_core_mv) {
411                 tegra_sdhci_platform_data0.nominal_vcore_mv = nominal_core_mv;
412                 tegra_sdhci_platform_data2.nominal_vcore_mv = nominal_core_mv;
413                 tegra_sdhci_platform_data3.nominal_vcore_mv = nominal_core_mv;
414         }
415         min_vcore_override_mv =
416                 tegra_dvfs_rail_get_override_floor(tegra_core_rail);
417         if (min_vcore_override_mv) {
418                 tegra_sdhci_platform_data0.min_vcore_override_mv =
419                         min_vcore_override_mv;
420                 tegra_sdhci_platform_data2.min_vcore_override_mv =
421                         min_vcore_override_mv;
422                 tegra_sdhci_platform_data3.min_vcore_override_mv =
423                         min_vcore_override_mv;
424         }
425         boot_vcore_mv = tegra_dvfs_rail_get_boot_level(tegra_core_rail);
426         if (boot_vcore_mv) {
427                 tegra_sdhci_platform_data0.boot_vcore_mv = boot_vcore_mv;
428                 tegra_sdhci_platform_data2.boot_vcore_mv = boot_vcore_mv;
429                 tegra_sdhci_platform_data3.boot_vcore_mv = boot_vcore_mv;
430         }
431
432         if (of_machine_is_compatible("nvidia,laguna") ||
433             of_machine_is_compatible("nvidia,jetson-tk1"))
434                 tegra_sdhci_platform_data2.wp_gpio = ARDBEG_SD_WP;
435
436         tegra_get_board_info(&board_info);
437         if (board_info.board_id == BOARD_E1780) {
438                 tegra_sdhci_platform_data3.max_clk_limit = 200000000;
439                 tegra_sdhci_platform_data2.max_clk_limit = 204000000;
440                 tegra_sdhci_platform_data0.max_clk_limit = 204000000;
441         } else {
442                 tegra_sdhci_platform_data3.uhs_mask = MMC_MASK_HS200;
443         }
444
445         if (board_info.board_id == BOARD_PM374 ||
446                 board_info.board_id == BOARD_PM358 ||
447                 board_info.board_id == BOARD_PM363 ||
448                 board_info.board_id == BOARD_PM359)
449                         tegra_sdhci_platform_data0.disable_clock_gate = 1;
450
451         speedo = tegra_fuse_readl(FUSE_SOC_SPEEDO_0);
452         tegra_sdhci_platform_data0.cpu_speedo = speedo;
453         tegra_sdhci_platform_data2.cpu_speedo = speedo;
454         tegra_sdhci_platform_data3.cpu_speedo = speedo;
455
456         speedo = tegra_fuse_readl(FUSE_SOC_SPEEDO_0);
457         tegra_sdhci_platform_data0.cpu_speedo = speedo;
458         tegra_sdhci_platform_data2.cpu_speedo = speedo;
459         tegra_sdhci_platform_data3.cpu_speedo = speedo;
460
461         platform_device_register(&tegra_sdhci_device3);
462         platform_device_register(&tegra_sdhci_device2);
463         if (board_info.board_id != BOARD_PM359 &&
464                         board_info.board_id != BOARD_PM375 &&
465                         board_info.board_id != BOARD_PM377) {
466                 platform_device_register(&tegra_sdhci_device0);
467                 ardbeg_wifi_init();
468         }
469
470         return 0;
471 }