From f2e8abd84467c8eed0178d64bbe88ce8e4765bd3 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 11 May 2010 17:28:51 -0700 Subject: [PATCH] [ARM] tegra: olympus: Add Wlan platform support Signed-off-by: Dmitry Shmidt --- arch/arm/configs/olympus_defconfig | 1 + arch/arm/include/asm/mach/mmc.h | 26 +++ arch/arm/mach-tegra/Kconfig | 5 + arch/arm/mach-tegra/Makefile | 1 + arch/arm/mach-tegra/board-olympus-pinmux.c | 4 +- arch/arm/mach-tegra/board-olympus-wifi.c | 212 +++++++++++++++++++++ arch/arm/mach-tegra/board-olympus.c | 5 +- arch/arm/mach-tegra/include/mach/sdhci.h | 2 + 8 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 arch/arm/include/asm/mach/mmc.h create mode 100644 arch/arm/mach-tegra/board-olympus-wifi.c diff --git a/arch/arm/configs/olympus_defconfig b/arch/arm/configs/olympus_defconfig index c968724218b6..2b63a00fc455 100644 --- a/arch/arm/configs/olympus_defconfig +++ b/arch/arm/configs/olympus_defconfig @@ -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 index 000000000000..8948dec26067 --- /dev/null +++ b/arch/arm/include/asm/mach/mmc.h @@ -0,0 +1,26 @@ +/* + * arch/arm/include/asm/mach/mmc.h + */ +#ifndef ASMARM_MACH_MMC_H +#define ASMARM_MACH_MMC_H + +#include +#include +#include + +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 diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index dc302a1961b3..2490112b5e6b 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -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 diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 00955988776a..9d17111912c0 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -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 diff --git a/arch/arm/mach-tegra/board-olympus-pinmux.c b/arch/arm/mach-tegra/board-olympus-pinmux.c index 893b0d3f2cde..947a1867faea 100644 --- a/arch/arm/mach-tegra/board-olympus-pinmux.c +++ b/arch/arm/mach-tegra/board-olympus-pinmux.c @@ -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 index 000000000000..19f37af1bfbb --- /dev/null +++ b/arch/arm/mach-tegra/board-olympus-wifi.c @@ -0,0 +1,212 @@ +/* linux/arch/arm/mach-msm/board-olympus-wifi.c +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); diff --git a/arch/arm/mach-tegra/board-olympus.c b/arch/arm/mach-tegra/board-olympus.c index 4a52e6996b98..2c44bbffa581 100644 --- a/arch/arm/mach-tegra/board-olympus.c +++ b/arch/arm/mach-tegra/board-olympus.c @@ -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); } diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h index 34e2686fca45..b0e07d26f161 100644 --- a/arch/arm/mach-tegra/include/mach/sdhci.h +++ b/arch/arm/mach-tegra/include/mach/sdhci.h @@ -18,6 +18,7 @@ #define __ASM_ARM_ARCH_TEGRA_SDHCI_H #include +#include 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 *); -- 2.34.1