407 lines
11 KiB
C
407 lines
11 KiB
C
|
|
||
|
#include <osl.h>
|
||
|
#include <dhd_linux.h>
|
||
|
#include <linux/gpio.h>
|
||
|
|
||
|
#ifdef CUSTOMER_HW_PLATFORM
|
||
|
#include <plat/sdhci.h>
|
||
|
#define sdmmc_channel sdmmc_device_mmc0
|
||
|
#endif /* CUSTOMER_HW_PLATFORM */
|
||
|
|
||
|
#if defined(BUS_POWER_RESTORE) && defined(BCMSDIO)
|
||
|
#include <linux/mmc/core.h>
|
||
|
#include <linux/mmc/card.h>
|
||
|
#include <linux/mmc/host.h>
|
||
|
#include <linux/mmc/sdio_func.h>
|
||
|
#endif /* defined(BUS_POWER_RESTORE) && defined(BCMSDIO) */
|
||
|
|
||
|
#ifdef CONFIG_DHD_USE_STATIC_BUF
|
||
|
extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
|
||
|
#endif /* CONFIG_DHD_USE_STATIC_BUF */
|
||
|
|
||
|
static int gpio_wl_reg_on = -1; // WL_REG_ON is input pin of WLAN module
|
||
|
#ifdef CUSTOMER_OOB
|
||
|
static int gpio_wl_host_wake = -1; // WL_HOST_WAKE is output pin of WLAN module
|
||
|
#endif
|
||
|
|
||
|
#ifdef CUSTOMER_HW_ALLWINNER
|
||
|
extern void sunxi_mmc_rescan_card(unsigned ids);
|
||
|
extern void sunxi_wlan_set_power(int on);
|
||
|
extern int sunxi_wlan_get_bus_index(void);
|
||
|
extern int sunxi_wlan_get_oob_irq(void);
|
||
|
extern int sunxi_wlan_get_oob_irq_flags(void);
|
||
|
|
||
|
/* Customer specifia wifi mac addr file */
|
||
|
#define WIFIMAC_PATH "/mnt/factory/ULI/factory/mac.txt"
|
||
|
#endif
|
||
|
|
||
|
static int
|
||
|
dhd_wlan_set_power(int on
|
||
|
#ifdef BUS_POWER_RESTORE
|
||
|
, wifi_adapter_info_t *adapter
|
||
|
#endif /* BUS_POWER_RESTORE */
|
||
|
)
|
||
|
{
|
||
|
int err = 0;
|
||
|
|
||
|
if (on) {
|
||
|
printf("======== PULL WL_REG_ON(%d) HIGH! ========\n", gpio_wl_reg_on);
|
||
|
if (gpio_wl_reg_on >= 0) {
|
||
|
err = gpio_direction_output(gpio_wl_reg_on, 1);
|
||
|
if (err) {
|
||
|
printf("%s: WL_REG_ON didn't output high\n", __FUNCTION__);
|
||
|
return -EIO;
|
||
|
}
|
||
|
}
|
||
|
#ifdef CUSTOMER_HW_ALLWINNER
|
||
|
sunxi_wlan_set_power(1);
|
||
|
#endif
|
||
|
#if defined(BUS_POWER_RESTORE)
|
||
|
#if defined(BCMSDIO)
|
||
|
if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) {
|
||
|
printf("======== mmc_power_restore_host! ========\n");
|
||
|
mmc_power_restore_host(adapter->sdio_func->card->host);
|
||
|
}
|
||
|
#elif defined(BCMPCIE)
|
||
|
OSL_SLEEP(50); /* delay needed to be able to restore PCIe configuration registers */
|
||
|
if (adapter->pci_dev) {
|
||
|
printf("======== pci_set_power_state PCI_D0! ========\n");
|
||
|
pci_set_power_state(adapter->pci_dev, PCI_D0);
|
||
|
if (adapter->pci_saved_state)
|
||
|
pci_load_and_free_saved_state(adapter->pci_dev, &adapter->pci_saved_state);
|
||
|
pci_restore_state(adapter->pci_dev);
|
||
|
err = pci_enable_device(adapter->pci_dev);
|
||
|
if (err < 0)
|
||
|
printf("%s: PCI enable device failed", __FUNCTION__);
|
||
|
pci_set_master(adapter->pci_dev);
|
||
|
}
|
||
|
#endif /* BCMPCIE */
|
||
|
#endif /* BUS_POWER_RESTORE */
|
||
|
/* Lets customer power to get stable */
|
||
|
mdelay(100);
|
||
|
} else {
|
||
|
#if defined(BUS_POWER_RESTORE)
|
||
|
#if defined(BCMSDIO)
|
||
|
if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) {
|
||
|
printf("======== mmc_power_save_host! ========\n");
|
||
|
mmc_power_save_host(adapter->sdio_func->card->host);
|
||
|
}
|
||
|
#elif defined(BCMPCIE)
|
||
|
if (adapter->pci_dev) {
|
||
|
printf("======== pci_set_power_state PCI_D3hot! ========\n");
|
||
|
pci_save_state(adapter->pci_dev);
|
||
|
adapter->pci_saved_state = pci_store_saved_state(adapter->pci_dev);
|
||
|
if (pci_is_enabled(adapter->pci_dev))
|
||
|
pci_disable_device(adapter->pci_dev);
|
||
|
pci_set_power_state(adapter->pci_dev, PCI_D3hot);
|
||
|
}
|
||
|
#endif /* BCMPCIE */
|
||
|
#endif /* BUS_POWER_RESTORE */
|
||
|
printf("======== PULL WL_REG_ON(%d) LOW! ========\n", gpio_wl_reg_on);
|
||
|
if (gpio_wl_reg_on >= 0) {
|
||
|
err = gpio_direction_output(gpio_wl_reg_on, 0);
|
||
|
if (err) {
|
||
|
printf("%s: WL_REG_ON didn't output low\n", __FUNCTION__);
|
||
|
return -EIO;
|
||
|
}
|
||
|
}
|
||
|
#ifdef CUSTOMER_HW_ALLWINNER
|
||
|
sunxi_wlan_set_power(0);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
static int dhd_wlan_set_reset(int onoff)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int dhd_wlan_set_carddetect(int present)
|
||
|
{
|
||
|
int err = 0;
|
||
|
#ifdef CUSTOMER_HW_ALLWINNER
|
||
|
int wlan_bus_index = sunxi_wlan_get_bus_index();
|
||
|
if(wlan_bus_index < 0)
|
||
|
return wlan_bus_index;
|
||
|
#endif
|
||
|
|
||
|
#if !defined(BUS_POWER_RESTORE)
|
||
|
if (present) {
|
||
|
#if defined(BCMSDIO)
|
||
|
printf("======== Card detection to detect SDIO card! ========\n");
|
||
|
#ifdef CUSTOMER_HW_PLATFORM
|
||
|
err = sdhci_force_presence_change(&sdmmc_channel, 1);
|
||
|
#endif /* CUSTOMER_HW_PLATFORM */
|
||
|
#ifdef CUSTOMER_HW_ALLWINNER
|
||
|
sunxi_mmc_rescan_card(wlan_bus_index);
|
||
|
#endif
|
||
|
#elif defined(BCMPCIE)
|
||
|
printf("======== Card detection to detect PCIE card! ========\n");
|
||
|
#endif
|
||
|
} else {
|
||
|
#if defined(BCMSDIO)
|
||
|
printf("======== Card detection to remove SDIO card! ========\n");
|
||
|
#ifdef CUSTOMER_HW_PLATFORM
|
||
|
err = sdhci_force_presence_change(&sdmmc_channel, 0);
|
||
|
#endif /* CUSTOMER_HW_PLATFORM */
|
||
|
#ifdef CUSTOMER_HW_ALLWINNER
|
||
|
sunxi_mmc_rescan_card(wlan_bus_index);
|
||
|
#endif
|
||
|
#elif defined(BCMPCIE)
|
||
|
printf("======== Card detection to remove PCIE card! ========\n");
|
||
|
#endif
|
||
|
}
|
||
|
#endif /* BUS_POWER_RESTORE */
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
static int dhd_wlan_get_mac_addr(unsigned char *buf)
|
||
|
{
|
||
|
int err = 0;
|
||
|
|
||
|
printf("======== %s ========\n", __FUNCTION__);
|
||
|
|
||
|
#ifdef CONFIG_ARCH_SUNXI
|
||
|
{
|
||
|
char *file_name = WIFIMAC_PATH;
|
||
|
void * fp = NULL;
|
||
|
char tmp_addr[18];
|
||
|
struct ether_addr tmp_ea;
|
||
|
char *str;
|
||
|
int i=0;
|
||
|
|
||
|
fp = dhd_os_open_image(file_name);
|
||
|
if (fp == NULL) {
|
||
|
printk("%s: Open wifi mac file failed %s\n", __FUNCTION__, file_name);
|
||
|
err = -EINVAL;
|
||
|
//goto end;
|
||
|
}
|
||
|
|
||
|
dhd_os_get_image_block(tmp_addr, 18, fp);
|
||
|
tmp_addr[17] = ':';
|
||
|
|
||
|
str = tmp_addr;
|
||
|
for (i=0; i<6; i++) {
|
||
|
tmp_ea.octet[i] = simple_strtoul(str, (char **)&str, 16 );
|
||
|
str++;
|
||
|
}
|
||
|
|
||
|
bcopy((char *)&tmp_ea, buf, sizeof(struct ether_addr));
|
||
|
char macpad[56]= {
|
||
|
0x00,0xaa,0x9c,0x84,0xc7,0xbc,0x9b,0xf6,
|
||
|
0x02,0x33,0xa9,0x4d,0x5c,0xb4,0x0a,0x5d,
|
||
|
0xa8,0xef,0xb0,0xcf,0x8e,0xbf,0x24,0x8a,
|
||
|
0x87,0x0f,0x6f,0x0d,0xeb,0x83,0x6a,0x70,
|
||
|
0x4a,0xeb,0xf6,0xe6,0x3c,0xe7,0x5f,0xfc,
|
||
|
0x0e,0xa7,0xb3,0x0f,0x00,0xe4,0x4a,0xaf,
|
||
|
0x87,0x08,0x16,0x6d,0x3a,0xe3,0xc7,0x80};
|
||
|
bcopy(macpad, buf+6, sizeof(macpad));
|
||
|
|
||
|
dhd_os_close_image(fp);
|
||
|
fp = NULL;
|
||
|
}
|
||
|
#endif /* CONFIG_ARCH_SUNXI */
|
||
|
|
||
|
#ifdef EXAMPLE_GET_MAC
|
||
|
/* EXAMPLE code */
|
||
|
{
|
||
|
struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}};
|
||
|
bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
|
||
|
}
|
||
|
#endif /* EXAMPLE_GET_MAC */
|
||
|
#ifdef EXAMPLE_GET_MAC_VER2
|
||
|
/* EXAMPLE code */
|
||
|
{
|
||
|
char macpad[56]= {
|
||
|
0x00,0xaa,0x9c,0x84,0xc7,0xbc,0x9b,0xf6,
|
||
|
0x02,0x33,0xa9,0x4d,0x5c,0xb4,0x0a,0x5d,
|
||
|
0xa8,0xef,0xb0,0xcf,0x8e,0xbf,0x24,0x8a,
|
||
|
0x87,0x0f,0x6f,0x0d,0xeb,0x83,0x6a,0x70,
|
||
|
0x4a,0xeb,0xf6,0xe6,0x3c,0xe7,0x5f,0xfc,
|
||
|
0x0e,0xa7,0xb3,0x0f,0x00,0xe4,0x4a,0xaf,
|
||
|
0x87,0x08,0x16,0x6d,0x3a,0xe3,0xc7,0x80};
|
||
|
bcopy(macpad, buf+6, sizeof(macpad));
|
||
|
}
|
||
|
#endif /* EXAMPLE_GET_MAC_VER2 */
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
static struct cntry_locales_custom brcm_wlan_translate_custom_table[] = {
|
||
|
/* Table should be filled out based on custom platform regulatory requirement */
|
||
|
#ifdef EXAMPLE_TABLE
|
||
|
{"", "XT", 49}, /* Universal if Country code is unknown or empty */
|
||
|
{"US", "US", 0},
|
||
|
#endif /* EXMAPLE_TABLE */
|
||
|
};
|
||
|
|
||
|
#ifdef CUSTOM_FORCE_NODFS_FLAG
|
||
|
struct cntry_locales_custom brcm_wlan_translate_nodfs_table[] = {
|
||
|
#ifdef EXAMPLE_TABLE
|
||
|
{"", "XT", 50}, /* Universal if Country code is unknown or empty */
|
||
|
{"US", "US", 0},
|
||
|
#endif /* EXMAPLE_TABLE */
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
static void *dhd_wlan_get_country_code(char *ccode
|
||
|
#ifdef CUSTOM_FORCE_NODFS_FLAG
|
||
|
, u32 flags
|
||
|
#endif
|
||
|
)
|
||
|
{
|
||
|
struct cntry_locales_custom *locales;
|
||
|
int size;
|
||
|
int i;
|
||
|
|
||
|
if (!ccode)
|
||
|
return NULL;
|
||
|
|
||
|
#ifdef CUSTOM_FORCE_NODFS_FLAG
|
||
|
if (flags & WLAN_PLAT_NODFS_FLAG) {
|
||
|
locales = brcm_wlan_translate_nodfs_table;
|
||
|
size = ARRAY_SIZE(brcm_wlan_translate_nodfs_table);
|
||
|
} else {
|
||
|
#endif
|
||
|
locales = brcm_wlan_translate_custom_table;
|
||
|
size = ARRAY_SIZE(brcm_wlan_translate_custom_table);
|
||
|
#ifdef CUSTOM_FORCE_NODFS_FLAG
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
for (i = 0; i < size; i++)
|
||
|
if (strcmp(ccode, locales[i].iso_abbrev) == 0)
|
||
|
return &locales[i];
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
struct resource dhd_wlan_resources[] = {
|
||
|
[0] = {
|
||
|
.name = "bcmdhd_wlan_irq",
|
||
|
.start = 0, /* Dummy */
|
||
|
.end = 0, /* Dummy */
|
||
|
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE
|
||
|
| IORESOURCE_IRQ_HIGHLEVEL, /* Dummy */
|
||
|
},
|
||
|
};
|
||
|
|
||
|
struct wifi_platform_data dhd_wlan_control = {
|
||
|
.set_power = dhd_wlan_set_power,
|
||
|
.set_reset = dhd_wlan_set_reset,
|
||
|
.set_carddetect = dhd_wlan_set_carddetect,
|
||
|
.get_mac_addr = dhd_wlan_get_mac_addr,
|
||
|
#ifdef CONFIG_DHD_USE_STATIC_BUF
|
||
|
.mem_prealloc = dhd_wlan_mem_prealloc,
|
||
|
#endif /* CONFIG_DHD_USE_STATIC_BUF */
|
||
|
.get_country_code = dhd_wlan_get_country_code,
|
||
|
};
|
||
|
|
||
|
int dhd_wlan_init_gpio(void)
|
||
|
{
|
||
|
int err = 0;
|
||
|
#ifdef CUSTOMER_OOB
|
||
|
int host_oob_irq = -1;
|
||
|
uint host_oob_irq_flags = 0;
|
||
|
#endif
|
||
|
|
||
|
/* Please check your schematic and fill right GPIO number which connected to
|
||
|
* WL_REG_ON and WL_HOST_WAKE.
|
||
|
*/
|
||
|
gpio_wl_reg_on = -1;
|
||
|
#ifdef CUSTOMER_OOB
|
||
|
gpio_wl_host_wake = -1;
|
||
|
#endif
|
||
|
|
||
|
if (gpio_wl_reg_on >= 0) {
|
||
|
err = gpio_request(gpio_wl_reg_on, "WL_REG_ON");
|
||
|
if (err < 0) {
|
||
|
printf("%s: gpio_request(%d) for WL_REG_ON failed\n",
|
||
|
__FUNCTION__, gpio_wl_reg_on);
|
||
|
gpio_wl_reg_on = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef CUSTOMER_OOB
|
||
|
if (gpio_wl_host_wake >= 0) {
|
||
|
err = gpio_request(gpio_wl_host_wake, "bcmdhd");
|
||
|
if (err < 0) {
|
||
|
printf("%s: gpio_request(%d) for WL_HOST_WAKE failed\n",
|
||
|
__FUNCTION__, gpio_wl_host_wake);
|
||
|
return -1;
|
||
|
}
|
||
|
err = gpio_direction_input(gpio_wl_host_wake);
|
||
|
if (err < 0) {
|
||
|
printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed\n",
|
||
|
__FUNCTION__, gpio_wl_host_wake);
|
||
|
gpio_free(gpio_wl_host_wake);
|
||
|
return -1;
|
||
|
}
|
||
|
host_oob_irq = gpio_to_irq(gpio_wl_host_wake);
|
||
|
if (host_oob_irq < 0) {
|
||
|
printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n",
|
||
|
__FUNCTION__, gpio_wl_host_wake);
|
||
|
gpio_free(gpio_wl_host_wake);
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
host_oob_irq = sunxi_wlan_get_oob_irq();
|
||
|
|
||
|
#ifdef HW_OOB
|
||
|
#ifdef HW_OOB_LOW_LEVEL
|
||
|
host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE;
|
||
|
#else
|
||
|
host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
|
||
|
#endif
|
||
|
#else
|
||
|
host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_SHAREABLE;
|
||
|
#endif
|
||
|
#ifdef CUSTOMER_HW_ALLWINNER
|
||
|
#ifdef HW_OOB
|
||
|
host_oob_irq_flags = sunxi_wlan_get_oob_irq_flags();
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
dhd_wlan_resources[0].start = dhd_wlan_resources[0].end = host_oob_irq;
|
||
|
dhd_wlan_resources[0].flags = host_oob_irq_flags;
|
||
|
printf("%s: WL_REG_ON=%d, WL_HOST_WAKE=%d\n", __FUNCTION__, gpio_wl_reg_on, gpio_wl_host_wake);
|
||
|
printf("%s: oob_irq=%d, oob_irq_flags=0x%x\n", __FUNCTION__, host_oob_irq, host_oob_irq_flags);
|
||
|
#endif /* CUSTOMER_OOB */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void dhd_wlan_deinit_gpio(void)
|
||
|
{
|
||
|
if (gpio_wl_reg_on >= 0) {
|
||
|
printf("%s: gpio_free(WL_REG_ON %d)\n", __FUNCTION__, gpio_wl_reg_on);
|
||
|
gpio_free(gpio_wl_reg_on);
|
||
|
gpio_wl_reg_on = -1;
|
||
|
}
|
||
|
#ifdef CUSTOMER_OOB
|
||
|
if (gpio_wl_host_wake >= 0) {
|
||
|
printf("%s: gpio_free(WL_HOST_WAKE %d)\n", __FUNCTION__, gpio_wl_host_wake);
|
||
|
gpio_free(gpio_wl_host_wake);
|
||
|
gpio_wl_host_wake = -1;
|
||
|
}
|
||
|
#endif /* CUSTOMER_OOB */
|
||
|
}
|
||
|
|
||
|
int dhd_wlan_init_plat_data(void)
|
||
|
{
|
||
|
int err = 0;
|
||
|
|
||
|
printf("======== %s ========\n", __FUNCTION__);
|
||
|
err = dhd_wlan_init_gpio();
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter)
|
||
|
{
|
||
|
printf("======== %s ========\n", __FUNCTION__);
|
||
|
dhd_wlan_deinit_gpio();
|
||
|
}
|
||
|
|