ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / board-ardbeg-sdhci.c
index 11f4175..80ea1e8 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/wl12xx.h>
 #include <linux/platform_data/mmc-sdhci-tegra.h>
 #include <linux/mfd/max77660/max77660-core.h>
+#include <linux/tegra-fuse.h>
 
 #include <asm/mach-types.h>
 #include <mach/irqs.h>
 #include "gpio-names.h"
 #include "board.h"
 #include "board-ardbeg.h"
+#include "dvfs.h"
 #include "iomap.h"
+#include "tegra-board-id.h"
 
 #define ARDBEG_WLAN_RST        TEGRA_GPIO_PCC5
 #define ARDBEG_WLAN_PWR        TEGRA_GPIO_PX7
 #define ARDBEG_WLAN_WOW        TEGRA_GPIO_PU5
+#if defined(CONFIG_BCMDHD_EDP_SUPPORT)
+#define ON 3070 /* 3069mW */
+#define OFF 0
+static unsigned int wifi_states[] = {ON, OFF};
+#endif
 
 #define ARDBEG_SD_CD   TEGRA_GPIO_PV2
+#define ARDBEG_SD_WP   TEGRA_GPIO_PQ4
+#define FUSE_SOC_SPEEDO_0      0x134
 
 static void (*wifi_status_cb)(int card_present, void *dev_id);
 static void *wifi_status_cb_devid;
@@ -50,11 +60,23 @@ static int ardbeg_wifi_status_register(void (*callback)(int , void *), void *);
 static int ardbeg_wifi_reset(int on);
 static int ardbeg_wifi_power(int on);
 static int ardbeg_wifi_set_carddetect(int val);
+static int ardbeg_wifi_get_mac_addr(unsigned char *buf);
 
 static struct wifi_platform_data ardbeg_wifi_control = {
        .set_power      = ardbeg_wifi_power,
        .set_reset      = ardbeg_wifi_reset,
        .set_carddetect = ardbeg_wifi_set_carddetect,
+       .get_mac_addr   = ardbeg_wifi_get_mac_addr,
+#if defined (CONFIG_BCMDHD_EDP_SUPPORT)
+       /* wifi edp client information */
+       .client_info    = {
+               .name           = "wifi_edp_client",
+               .states         = wifi_states,
+               .num_states     = ARRAY_SIZE(wifi_states),
+               .e0_index       = 0,
+               .priority       = EDP_MAX_PRIO,
+       },
+#endif
 };
 
 static struct resource wifi_resource[] = {
@@ -75,6 +97,23 @@ static struct platform_device ardbeg_wifi_device = {
        },
 };
 
+static struct resource mrvl_wifi_resource[] = {
+       [0] = {
+               .name   = "mrvl_wlan_irq",
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE,
+       },
+};
+
+static struct platform_device marvell_wifi_device = {
+       .name           = "mrvl_wlan",
+       .id             = 1,
+       .num_resources  = 1,
+       .resource       = mrvl_wifi_resource,
+       .dev            = {
+               .platform_data = &ardbeg_wifi_control,
+       },
+};
+
 static struct resource sdhci_resource0[] = {
        [0] = {
                .start  = INT_SDMMC1,
@@ -146,8 +185,10 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
        .tap_delay = 0,
        .trim_delay = 0x2,
        .ddr_clk_limit = 41000000,
-       .uhs_mask = MMC_UHS_MASK_SDR104 |
-               MMC_UHS_MASK_DDR50 | MMC_UHS_MASK_SDR50,
+       .uhs_mask = MMC_UHS_MASK_DDR50 |
+               MMC_UHS_MASK_SDR50,
+       .calib_3v3_offsets = 0x7676,
+       .calib_1v8_offsets = 0x7676,
 };
 
 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
@@ -156,9 +197,9 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
        .power_gpio = -1,
        .tap_delay = 0,
        .trim_delay = 0x3,
-       .uhs_mask = MMC_UHS_MASK_SDR104 |
-               MMC_UHS_MASK_DDR50 | MMC_UHS_MASK_SDR50,
-/*     .max_clk = 12000000, */
+       .uhs_mask = MMC_UHS_MASK_DDR50,
+       .calib_3v3_offsets = 0x7676,
+       .calib_1v8_offsets = 0x7676,
 };
 
 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
@@ -167,16 +208,16 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
        .power_gpio = -1,
        .is_8bit = 1,
        .tap_delay = 0x4,
-       .trim_delay = 0x4,
-       .ddr_trim_delay = 0x4,
+       .trim_delay = 0x3,
+       .ddr_trim_delay = 0x0,
        .mmc_data = {
                .built_in = 1,
                .ocr_mask = MMC_OCR_1V8_MASK,
        },
-       .uhs_mask = MMC_MASK_HS200,
        .ddr_clk_limit = 51000000,
        .max_clk_limit = 102000000,
-/*     .max_clk = 12000000, */
+       .calib_3v3_offsets = 0x0202,
+       .calib_1v8_offsets = 0x0202,
 };
 
 static struct platform_device tegra_sdhci_device0 = {
@@ -247,6 +288,60 @@ static int ardbeg_wifi_reset(int on)
        return 0;
 }
 
+#define ARDBEG_WIFI_MAC_ADDR_FILE      "/mnt/factory/wifi/wifi_mac.txt"
+
+static int ardbeg_wifi_get_mac_addr(unsigned char *buf)
+{
+       struct file *fp;
+       int rdlen;
+       char str[32];
+       int mac[6];
+       int ret = 0;
+
+       pr_debug("%s\n", __func__);
+
+       /* open wifi mac address file */
+       fp = filp_open(ARDBEG_WIFI_MAC_ADDR_FILE, O_RDONLY, 0);
+       if (IS_ERR(fp)) {
+               pr_err("%s: cannot open %s\n",
+                       __func__, ARDBEG_WIFI_MAC_ADDR_FILE);
+               return -ENOENT;
+       }
+
+       /* read wifi mac address file */
+       memset(str, 0, sizeof(str));
+       rdlen = kernel_read(fp, fp->f_pos, str, 17);
+       if (rdlen > 0)
+               fp->f_pos += rdlen;
+       if (rdlen != 17) {
+               pr_err("%s: bad mac address file"
+                       " - len %d < 17",
+                       __func__, rdlen);
+               ret = -ENOENT;
+       } else if (sscanf(str, "%x:%x:%x:%x:%x:%x",
+               &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
+               pr_err("%s: bad mac address file"
+                       " - must contain xx:xx:xx:xx:xx:xx\n",
+                       __func__);
+               ret = -ENOENT;
+       } else {
+               pr_info("%s: using wifi mac %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       __func__,
+                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+               buf[0] = (unsigned char) mac[0];
+               buf[1] = (unsigned char) mac[1];
+               buf[2] = (unsigned char) mac[2];
+               buf[3] = (unsigned char) mac[3];
+               buf[4] = (unsigned char) mac[4];
+               buf[5] = (unsigned char) mac[5];
+       }
+
+       /* close wifi mac address file */
+       filp_close(fp, NULL);
+
+       return ret;
+}
+
 static int __init ardbeg_wifi_init(void)
 {
        int rc;
@@ -276,13 +371,23 @@ static int __init ardbeg_wifi_init(void)
                gpio_to_irq(ARDBEG_WLAN_WOW);
 
        platform_device_register(&ardbeg_wifi_device);
+
+       mrvl_wifi_resource[0].start = mrvl_wifi_resource[0].end =
+               gpio_to_irq(ARDBEG_WLAN_WOW);
+       platform_device_register(&marvell_wifi_device);
+
        return 0;
 }
 
 #ifdef CONFIG_TEGRA_PREPOWER_WIFI
 static int __init ardbeg_wifi_prepower(void)
 {
-       if (!of_machine_is_compatible("nvidia,ardbeg"))
+       if (!of_machine_is_compatible("nvidia,ardbeg") &&
+               !of_machine_is_compatible("nvidia,laguna") &&
+               !of_machine_is_compatible("nvidia,ardbeg_sata") &&
+               !of_machine_is_compatible("nvidia,tn8") &&
+               !of_machine_is_compatible("nvidia,norrin") &&
+               !of_machine_is_compatible("nvidia,jetson-tk1"))
                return 0;
        ardbeg_wifi_power(1);
 
@@ -294,10 +399,81 @@ subsys_initcall_sync(ardbeg_wifi_prepower);
 
 int __init ardbeg_sdhci_init(void)
 {
+       int nominal_core_mv;
+       int min_vcore_override_mv;
+       int boot_vcore_mv;
+       u32 speedo;
+       struct board_info board_info;
+
+       nominal_core_mv =
+               tegra_dvfs_rail_get_nominal_millivolts(tegra_core_rail);
+       if (nominal_core_mv) {
+               tegra_sdhci_platform_data0.nominal_vcore_mv = nominal_core_mv;
+               tegra_sdhci_platform_data2.nominal_vcore_mv = nominal_core_mv;
+               tegra_sdhci_platform_data3.nominal_vcore_mv = nominal_core_mv;
+       }
+       min_vcore_override_mv =
+               tegra_dvfs_rail_get_override_floor(tegra_core_rail);
+       if (min_vcore_override_mv) {
+               tegra_sdhci_platform_data0.min_vcore_override_mv =
+                       min_vcore_override_mv;
+               tegra_sdhci_platform_data2.min_vcore_override_mv =
+                       min_vcore_override_mv;
+               tegra_sdhci_platform_data3.min_vcore_override_mv =
+                       min_vcore_override_mv;
+       }
+       boot_vcore_mv = tegra_dvfs_rail_get_boot_level(tegra_core_rail);
+       if (boot_vcore_mv) {
+               tegra_sdhci_platform_data0.boot_vcore_mv = boot_vcore_mv;
+               tegra_sdhci_platform_data2.boot_vcore_mv = boot_vcore_mv;
+               tegra_sdhci_platform_data3.boot_vcore_mv = boot_vcore_mv;
+       }
+
+       if (of_machine_is_compatible("nvidia,laguna") ||
+           of_machine_is_compatible("nvidia,jetson-tk1"))
+               tegra_sdhci_platform_data2.wp_gpio = ARDBEG_SD_WP;
+
+       tegra_get_board_info(&board_info);
+       if (board_info.board_id == BOARD_E1780) {
+               tegra_sdhci_platform_data3.max_clk_limit = 200000000;
+               tegra_sdhci_platform_data2.max_clk_limit = 204000000;
+               tegra_sdhci_platform_data0.max_clk_limit = 204000000;
+       } else {
+               tegra_sdhci_platform_data3.uhs_mask = MMC_MASK_HS200;
+       }
+
+       if (board_info.board_id == BOARD_PM374 ||
+               board_info.board_id == BOARD_PM358 ||
+               board_info.board_id == BOARD_PM363 ||
+               board_info.board_id == BOARD_PM359)
+                       tegra_sdhci_platform_data0.disable_clock_gate = 1;
+
+       /*
+        * FIXME: Set max clk limit to 200MHz for SDMMC3 for PM375.
+        * Requesting 208MHz results in getting 204MHz from PLL_P
+        * and CRC errors are seen with same.
+        */
+       if (board_info.board_id == BOARD_PM375)
+               tegra_sdhci_platform_data2.max_clk_limit = 200000000;
+
+       speedo = tegra_fuse_readl(FUSE_SOC_SPEEDO_0);
+       tegra_sdhci_platform_data0.cpu_speedo = speedo;
+       tegra_sdhci_platform_data2.cpu_speedo = speedo;
+       tegra_sdhci_platform_data3.cpu_speedo = speedo;
+
+       speedo = tegra_fuse_readl(FUSE_SOC_SPEEDO_0);
+       tegra_sdhci_platform_data0.cpu_speedo = speedo;
+       tegra_sdhci_platform_data2.cpu_speedo = speedo;
+       tegra_sdhci_platform_data3.cpu_speedo = speedo;
+
        platform_device_register(&tegra_sdhci_device3);
        platform_device_register(&tegra_sdhci_device2);
-       platform_device_register(&tegra_sdhci_device0);
-       ardbeg_wifi_init();
+       if (board_info.board_id != BOARD_PM359 &&
+                       board_info.board_id != BOARD_PM375 &&
+                       board_info.board_id != BOARD_PM377) {
+               platform_device_register(&tegra_sdhci_device0);
+               ardbeg_wifi_init();
+       }
 
        return 0;
 }