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