[ARM] tegra: olympus: Add Wlan platform support
authorDmitry Shmidt <dimitrysh@google.com>
Wed, 12 May 2010 00:28:51 +0000 (17:28 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:32:53 +0000 (16:32 -0700)
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
arch/arm/configs/olympus_defconfig
arch/arm/include/asm/mach/mmc.h [new file with mode: 0644]
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/board-olympus-pinmux.c
arch/arm/mach-tegra/board-olympus-wifi.c [new file with mode: 0644]
arch/arm/mach-tegra/board-olympus.c
arch/arm/mach-tegra/include/mach/sdhci.h

index c968724218b604b70c57fedf12580e44abb74bbd..2b63a00fc455d5e432fd46ce2fd4597e608ff91f 100644 (file)
@@ -258,6 +258,7 @@ CONFIG_TEGRA_DEBUG_UARTB=y
 # CONFIG_TEGRA_DEBUG_UARTD is not set
 # CONFIG_TEGRA_DEBUG_UARTE is not set
 CONFIG_TEGRA_SYSTEM_DMA=y
+CONFIG_WIFI_CONTROL_FUNC=y
 
 #
 # Processor Type
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
new file mode 100644 (file)
index 0000000..8948dec
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *  arch/arm/include/asm/mach/mmc.h
+ */
+#ifndef ASMARM_MACH_MMC_H
+#define ASMARM_MACH_MMC_H
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+
+struct embedded_sdio_data {
+        struct sdio_cis cis;
+        struct sdio_cccr cccr;
+        struct sdio_embedded_func *funcs;
+        int num_funcs;
+};
+
+struct mmc_platform_data {
+       unsigned int ocr_mask;                  /* available voltages */
+       u32 (*translate_vdd)(struct device *, unsigned int);
+       unsigned int (*status)(struct device *);
+       struct embedded_sdio_data *embedded_sdio;
+       int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
+};
+
+#endif
index dc302a1961b322f538b790ca314c6162b7ea56b8..2490112b5e6b360d837283f161757c539a90e3d1 100644 (file)
@@ -73,6 +73,11 @@ config TEGRA_PWM
        help
          Enable support for the Tegra PWM controller(s).
 
+config WIFI_CONTROL_FUNC
+       bool "Enable WiFi control function abstraction"
+       help
+         Enables Power/Reset/Carddetect function abstraction
+
 endif
 
 config TEGRA_IOVMM_GART
index 00955988776aafc9165c4a667eb4e79f957b62f1..9d17111912c04223a2ca03b536866fd0e2756b3d 100644 (file)
@@ -49,3 +49,4 @@ obj-${CONFIG_MACH_OLYMPUS}              += board-olympus-pinmux.o
 obj-${CONFIG_MACH_OLYMPUS}              += board-olympus-panel.o
 obj-${CONFIG_MACH_OLYMPUS}              += board-olympus-i2c.o
 obj-${CONFIG_MACH_OLYMPUS}              += board-olympus-keypad.o
+obj-${CONFIG_MACH_OLYMPUS}              += board-olympus-wifi.o
index 893b0d3f2cdebe9a1fbfca2cb704279cb48af9ba..947a1867faea779cfa9ffb656443c9d08917c713 100644 (file)
@@ -45,7 +45,7 @@ static struct tegra_pingroup_config olympus_pinmux[] = {
        {TEGRA_PINGROUP_GMC,   TEGRA_MUX_UARTD,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_GMD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_GME,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-       {TEGRA_PINGROUP_GPU,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_GPU,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_GPU7,  TEGRA_MUX_RTCK,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
@@ -105,7 +105,7 @@ static struct tegra_pingroup_config olympus_pinmux[] = {
        {TEGRA_PINGROUP_SDB,   TEGRA_MUX_SDIO3,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_SDC,   TEGRA_MUX_SDIO3,         TEGRA_TRI_NORMAL,     TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_SDD,   TEGRA_MUX_SDIO3,         TEGRA_TRI_NORMAL,     TEGRA_TRI_NORMAL},
-       {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SLXC,  TEGRA_MUX_SPI4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SLXD,  TEGRA_MUX_SPI4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
diff --git a/arch/arm/mach-tegra/board-olympus-wifi.c b/arch/arm/mach-tegra/board-olympus-wifi.c
new file mode 100644 (file)
index 0000000..19f37af
--- /dev/null
@@ -0,0 +1,212 @@
+/* linux/arch/arm/mach-msm/board-olympus-wifi.c
+*/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/mach-types.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/skbuff.h>
+#include <linux/wlan_plat.h>
+#include <mach/sdhci.h>
+
+#include "gpio-names.h"
+
+#define OLYMPUS_WLAN_IRQ       TEGRA_GPIO_PU5
+#define OLYMPUS_WLAN_PWR       TEGRA_GPIO_PU3
+#define OLYMPUS_WLAN_RST       TEGRA_GPIO_PU2
+
+#define PREALLOC_WLAN_NUMBER_OF_SECTIONS       4
+#define PREALLOC_WLAN_NUMBER_OF_BUFFERS                160
+#define PREALLOC_WLAN_SECTION_HEADER           24
+
+#define WLAN_SECTION_SIZE_0    (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
+#define WLAN_SECTION_SIZE_1    (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
+#define WLAN_SECTION_SIZE_2    (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 512)
+#define WLAN_SECTION_SIZE_3    (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 1024)
+
+#define WLAN_SKB_BUF_NUM       16
+
+static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
+
+typedef struct wifi_mem_prealloc_struct {
+       void *mem_ptr;
+       unsigned long size;
+} wifi_mem_prealloc_t;
+
+static wifi_mem_prealloc_t wifi_mem_array[PREALLOC_WLAN_NUMBER_OF_SECTIONS] = {
+       { NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER) },
+       { NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER) },
+       { NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER) },
+       { NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER) }
+};
+
+static void *olympus_wifi_mem_prealloc(int section, unsigned long size)
+{
+       if (section == PREALLOC_WLAN_NUMBER_OF_SECTIONS)
+               return wlan_static_skb;
+       if ((section < 0) || (section > PREALLOC_WLAN_NUMBER_OF_SECTIONS))
+               return NULL;
+       if (wifi_mem_array[section].size < size)
+               return NULL;
+       return wifi_mem_array[section].mem_ptr;
+}
+
+int __init olympus_init_wifi_mem(void)
+{
+       int i;
+
+       for(i=0;( i < WLAN_SKB_BUF_NUM );i++) {
+               if (i < (WLAN_SKB_BUF_NUM/2))
+                       wlan_static_skb[i] = dev_alloc_skb(4096);
+               else
+                       wlan_static_skb[i] = dev_alloc_skb(8192);
+       }
+       for(i=0;( i < PREALLOC_WLAN_NUMBER_OF_SECTIONS );i++) {
+               wifi_mem_array[i].mem_ptr = kmalloc(wifi_mem_array[i].size,
+                                                       GFP_KERNEL);
+               if (wifi_mem_array[i].mem_ptr == NULL)
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+static struct resource olympus_wifi_resources[] = {
+       [0] = {
+               .name           = "bcm4329_wlan_irq",
+               .start          = TEGRA_GPIO_TO_IRQ(OLYMPUS_WLAN_IRQ),
+               .end            = TEGRA_GPIO_TO_IRQ(OLYMPUS_WLAN_IRQ),
+               .flags          = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+       },
+};
+
+/* BCM4329 returns wrong sdio_vsn(1) when we read cccr,
+ * we use predefined value (sdio_vsn=2) here to initial sdio driver well
+  */
+static struct embedded_sdio_data olympus_wifi_emb_data = {
+       .cccr   = {
+               .sdio_vsn       = 2,
+               .multi_block    = 1,
+               .low_speed      = 0,
+               .wide_bus       = 0,
+               .high_power     = 1,
+               .high_speed     = 1,
+       },
+};
+
+static int olympus_wifi_cd = 0; /* WIFI virtual 'card detect' status */
+static void (*wifi_status_cb)(int card_present, void *dev_id);
+static void *wifi_status_cb_devid;
+
+static int olympus_wifi_status_register(
+               void (*callback)(int card_present, void *dev_id),
+               void *dev_id)
+{
+       if (wifi_status_cb)
+               return -EAGAIN;
+       wifi_status_cb = callback;
+       wifi_status_cb_devid = dev_id;
+       return 0;
+}
+
+static unsigned int olympus_wifi_status(struct device *dev)
+{
+       return olympus_wifi_cd;
+}
+
+struct tegra_sdhci_platform_data olympus_wifi_data = {
+       .clk_id = NULL,
+       .force_hs = 0,
+       .mmc_data = {
+               .ocr_mask               = MMC_VDD_165_195,
+               .status                 = olympus_wifi_status,
+               .register_status_notify = olympus_wifi_status_register,
+               .embedded_sdio          = &olympus_wifi_emb_data,
+       }
+};
+
+int olympus_wifi_set_carddetect(int val)
+{
+       pr_debug("%s: %d\n", __func__, val);
+       olympus_wifi_cd = val;
+       if (wifi_status_cb) {
+               wifi_status_cb(val, wifi_status_cb_devid);
+       } else
+               pr_warning("%s: Nobody to notify\n", __func__);
+       return 0;
+}
+
+static int olympus_wifi_power_state;
+
+int olympus_wifi_power(int on)
+{
+       pr_debug("%s: %d\n", __func__, on);
+
+       mdelay(100);
+       gpio_set_value(OLYMPUS_WLAN_PWR, on);
+       mdelay(100);
+       gpio_set_value(OLYMPUS_WLAN_RST, on);
+       mdelay(200);
+
+       olympus_wifi_power_state = on;
+       return 0;
+}
+
+static int olympus_wifi_reset_state;
+
+int olympus_wifi_reset(int on)
+{
+       pr_debug("%s: do nothing\n", __func__);
+       olympus_wifi_reset_state = on;
+       return 0;
+}
+
+static struct wifi_platform_data olympus_wifi_control = {
+       .set_power      = olympus_wifi_power,
+       .set_reset      = olympus_wifi_reset,
+       .set_carddetect = olympus_wifi_set_carddetect,
+       .mem_prealloc   = olympus_wifi_mem_prealloc,
+};
+
+static struct platform_device olympus_wifi_device = {
+        .name           = "bcm4329_wlan",
+        .id             = 1,
+        .num_resources  = ARRAY_SIZE(olympus_wifi_resources),
+        .resource       = olympus_wifi_resources,
+        .dev            = {
+                .platform_data = &olympus_wifi_control,
+        },
+};
+
+static void __init olympus_wlan_gpio(void)
+{
+       tegra_gpio_enable(OLYMPUS_WLAN_PWR);
+       gpio_request(OLYMPUS_WLAN_PWR, "wlan_pwr");
+       gpio_direction_output(OLYMPUS_WLAN_PWR, 0);
+
+       tegra_gpio_enable(OLYMPUS_WLAN_RST);
+       gpio_request(OLYMPUS_WLAN_RST, "wlan_rst");
+       gpio_direction_output(OLYMPUS_WLAN_RST, 0);
+
+       tegra_gpio_enable(OLYMPUS_WLAN_IRQ);
+       gpio_request(OLYMPUS_WLAN_IRQ, "wlan_irq");
+       gpio_direction_input(OLYMPUS_WLAN_IRQ);
+}
+
+static int __init olympus_wlan_init(void)
+{
+       int ret;
+
+       if (!machine_is_olympus())
+               return 0;
+
+       pr_debug("%s: start\n", __func__);
+       olympus_wlan_gpio();
+       olympus_init_wifi_mem();
+       ret = platform_device_register(&olympus_wifi_device);
+       return ret;
+}
+
+late_initcall(olympus_wlan_init);
index 4a52e6996b9828e514b6795bb8b2663f80625873..2c44bbffa58160ff03af47d5539a92f405754865 100644 (file)
@@ -203,6 +203,8 @@ static struct platform_device *olympus_devices[] __initdata = {
        &hsuart,
 };
 
+extern struct tegra_sdhci_platform_data olympus_wifi_data; /* sdhci1 */
+
 static struct tegra_sdhci_platform_data olympus_sdhci_platform_data3 = {
        .clk_id = NULL,
        .force_hs = 0,
@@ -220,10 +222,11 @@ static struct tegra_sdhci_platform_data olympus_sdhci_platform_data4 = {
 static void olympus_sdhci_init(void)
 {
        /* TODO: setup GPIOs for cd, wd, and power */
+       tegra_sdhci_device1.dev.platform_data = &olympus_wifi_data;
        tegra_sdhci_device3.dev.platform_data = &olympus_sdhci_platform_data3;
        tegra_sdhci_device4.dev.platform_data = &olympus_sdhci_platform_data4;
 
-
+       platform_device_register(&tegra_sdhci_device1);
        platform_device_register(&tegra_sdhci_device3);
        platform_device_register(&tegra_sdhci_device4);
 }
index 34e2686fca454f0cc1a649aa69e5cd5f4397264e..b0e07d26f1612a3dff9d8074089c28d1e7c80ce8 100644 (file)
@@ -18,6 +18,7 @@
 #define __ASM_ARM_ARCH_TEGRA_SDHCI_H
 
 #include <linux/mmc/host.h>
+#include <asm/mach/mmc.h>
 
 struct tegra_sdhci_platform_data {
        const char *clk_id;
@@ -25,6 +26,7 @@ struct tegra_sdhci_platform_data {
        int cd_gpio;
        int wp_gpio;
        int power_gpio;
+       struct mmc_platform_data mmc_data;
 
        void (*board_probe)(int id, struct mmc_host *);
        void (*board_remove)(int id, struct mmc_host *);