add sdio wifi power

This commit is contained in:
林辉辉
2010-06-03 03:00:59 +00:00
committed by 黄涛
parent d9c863aae3
commit e221fe7e0a
8 changed files with 252 additions and 1182 deletions

View File

@@ -162,7 +162,7 @@ void rk2818_sdmmc1_cfg_gpio(struct platform_device *dev)
{
rk2818_mux_api_set(GPIOG_MMC1_SEL_NAME, IOMUXA_SDMMC1_CMD_DATA0_CLKOUT);
rk2818_mux_api_set(GPIOG_MMC1D_SEL_NAME, IOMUXA_SDMMC1_DATA123);
#if 1
#if 0
/* wifi power up (gpio control) */
rk2818_mux_api_set(GPIOH7_HSADCCLK_SEL_NAME,IOMUXB_GPIO1_D7);
rk2818_mux_api_set(GPIOF5_APWM3_DPWM3_NAME,IOMUXB_GPIO1_B5);

View File

@@ -38,6 +38,8 @@
#include "rk2818-sdmmc.h"
struct mmc_host *wifi_mmc_host = NULL;
#define RK2818_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | SDMMC_INT_HTO | SDMMC_INT_SBE | SDMMC_INT_EBE)
#define RK2818_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | SDMMC_INT_RE | SDMMC_INT_HLE)
#define RK2818_MCI_ERROR_FLAGS (RK2818_MCI_DATA_ERROR_FLAGS | RK2818_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE)
@@ -1300,6 +1302,8 @@ static int rk2818_sdmmc_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "RK2818 MMC controller used as %s, at irq %d\n",
host->dma_name, host->irq);
if (strncmp(host->dma_name, "sdio", 4) == 0)
wifi_mmc_host = mmc;
return 0;
@@ -1321,6 +1325,9 @@ static int __exit rk2818_sdmmc_remove(struct platform_device *pdev)
{
struct rk2818_sdmmc_host *host = platform_get_drvdata(pdev);
if (strncmp(host->dma_name, "sdio", 4) == 0)
wifi_mmc_host = NULL;
writel(0xFFFFFFFF, host->regs + SDMMC_RINTSTS);
writel(0, host->regs + SDMMC_INTMASK); // disable all mmc interrupt first

View File

@@ -9,5 +9,5 @@ libertas_spi-objs += if_spi.o
obj-$(CONFIG_LIBERTAS) += libertas.o
obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o
obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o wifi_power.o
obj-$(CONFIG_LIBERTAS_SPI) += libertas_spi.o

File diff suppressed because it is too large Load Diff

View File

@@ -34,6 +34,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/host.h>
#include "host.h"
#include "decl.h"
@@ -41,6 +42,9 @@
#include "dev.h"
#include "cmd.h"
#include "if_sdio.h"
#include "wifi_power.h"
extern struct mmc_host *wifi_mmc_host;
/* The if_sdio_remove() callback function is called when
* user removes this module from kernel space or ejects
@@ -1141,21 +1145,48 @@ static struct sdio_driver if_sdio_driver = {
//static int __init if_sdio_init_module2(void)
//void if_sdio_init_module2(struct work_struct *work)
int wifi_no_power_gpio = 0; /* 0-No 1-Yes */
void if_sdio_init_module2(void)
{
int ret = 0;
lbs_deb_enter(LBS_DEB_SDIO);
int ret = 0,timeout;
wifi_sdio_func = NULL;
wifi_no_power_gpio = 0;
//lbs_deb_enter(LBS_DEB_SDIO);
printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");
printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");
ret = sdio_register_driver(&if_sdio_driver);
/* Clear the flag in case user removes the card. */
user_rmmod = 0;
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
///lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
ret = sdio_register_driver(&if_sdio_driver);
#ifdef WIFI_GPIO_POWER_CONTROL
if (wifi_mmc_host->bus_ops != NULL) /* mmc/card is attached already. */
{
printk("SDIO maybe be attached already.\n");
wifi_no_power_gpio = 1;
return ;
}
wifi_turn_on_card();
wifi_power_up_wifi();
mmc_detect_change(wifi_mmc_host, 2);
for (timeout = 100; timeout >=0; timeout--)
{
if (wifi_sdio_func != NULL)
break;
msleep(50);
}
if (timeout <= 0)
printk("No WiFi function card has been attached.\n");
#endif
return ;
}
EXPORT_SYMBOL(if_sdio_init_module2);
@@ -1173,20 +1204,47 @@ static int __init if_sdio_init_module(void)
#endif
static void __exit if_sdio_exit_module(void)
void if_sdio_exit_module(void)
{
int timeout;
lbs_deb_enter(LBS_DEB_SDIO);
/* Set the flag as user is removing this module. */
user_rmmod = 1;
sdio_unregister_driver(&if_sdio_driver);
#ifdef WIFI_GPIO_POWER_CONTROL
if (wifi_no_power_gpio == 1)
return;
if (wifi_mmc_host == NULL)
{
printk("No SDIO host is present.\n");
return;
}
wifi_power_down_wifi();
wifi_turn_off_card();
mmc_detect_change(wifi_mmc_host, 2);
for (timeout = 50; timeout >= 0; timeout--)
{
msleep(100);
if (wifi_mmc_host->bus_ops == NULL)
break;
}
if (timeout < 0)
printk("Fail to release SDIO card.\n");
#endif
lbs_deb_leave(LBS_DEB_SDIO);
}
EXPORT_SYMBOL(if_sdio_exit_module);
//module_init(if_sdio_init_module);
module_exit(if_sdio_exit_module);
//module_exit(if_sdio_exit_module);
MODULE_DESCRIPTION("Libertas SDIO WLAN Driver");
MODULE_AUTHOR("Pierre Ossman");

View File

@@ -0,0 +1,110 @@
/*
* wifi_power.c
*
* Power control for WIFI module.
*
* There are Power supply and Power Up/Down controls for WIFI typically.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include "wifi_power.h"
#if (WIFI_GPIO_POWER_CONTROL == 1)
struct wifi_power power_gpio =
{
POWER_USE_GPIO, POWER_GPIO_IOMUX, GPIOH7_HSADCCLK_SEL_NAME,
IOMUXB_GPIO1_D7, RK2818_PIN_PH7, GPIO_HIGH
};
struct wifi_power power_save_gpio =
{
0, 0, 0, 0, 0, 0
};
int wifi_gpio_operate(struct wifi_power *gpio, int flag)
{
int sensitive;
if (gpio->use_gpio == POWER_NOT_USE_GPIO)
return 0;
if (gpio->gpio_iomux == POWER_GPIO_IOMUX)
{
rk2818_mux_api_set(gpio->iomux_name, gpio->iomux_value);
}
if (flag == GPIO_SWITCH_ON)
sensitive = gpio->sensi_level;
else
sensitive = 1 - gpio->sensi_level;
gpio_request(gpio->gpio_id, "wifi_power");
gpio_direction_output(gpio->gpio_id,sensitive);
return 0;
}
int wifi_turn_on_card(void)
{
if (wifi_gpio_operate(&power_gpio, GPIO_SWITCH_ON) != 0)
{
printk("Couldn't set GPIO [ON] successfully for power supply.\n");
return -1;
}
return 0;
}
int wifi_turn_off_card(void)
{
if (wifi_gpio_operate(&power_gpio, GPIO_SWITCH_OFF) != 0)
{
printk("Couldn't set GPIO [OFF] successfully for power supply.\n");
return -1;
}
return 0;
}
int wifi_power_up_wifi(void)
{
if (wifi_gpio_operate(&power_save_gpio, GPIO_SWITCH_ON) != 0)
{
printk("Couldn't set GPIO [ON] successfully for power up.\n");
return -1;
}
mdelay(5);
if (wifi_gpio_operate(&power_save_gpio, GPIO_SWITCH_OFF) != 0)
{
printk("Couldn't set GPIO [ON] successfully for power up.\n");
return -1;
}
msleep(150);
if (wifi_gpio_operate(&power_save_gpio, GPIO_SWITCH_ON) != 0)
{
printk("Couldn't set GPIO [ON] successfully for power up.\n");
return -1;
}
msleep(50);
return 0;
}
int wifi_power_down_wifi(void)
{
if (wifi_gpio_operate(&power_save_gpio, GPIO_SWITCH_OFF) != 0)
{
printk("Couldn't set GPIO [OFF] successfully for power down.\n");
return -1;
}
return 0;
}
#endif /* WIFI_GPIO_POWER_CONTROL */

View File

@@ -0,0 +1,56 @@
/*
* wifi_power.h
*
* WIFI power control.
*
* Yongle Lai
*/
#ifndef WIFI_POWER_H
#define WIFI_POWER_H
#define WIFI_GPIO_POWER_CONTROL 1
#if (WIFI_GPIO_POWER_CONTROL == 1)
#include <mach/gpio.h>
#include <mach/iomux.h>
#define POWER_NOT_USE_GPIO 0
#define POWER_USE_GPIO 1
#define POWER_GPIO_NOT_IOMUX 0
#define POWER_GPIO_IOMUX 1
#define GPIO_SWITCH_OFF 0
#define GPIO_SWITCH_ON 1
struct wifi_power
{
u8 use_gpio; /* If uses GPIO to control wifi power supply. 0 - no, 1 - yes. */
u8 gpio_iomux; /* If the GPIO is iomux. 0 - no, 1 - yes. */
char *iomux_name; /* IOMUX name */
u8 iomux_value; /* IOMUX value - which function is choosen. */
u8 gpio_id; /* GPIO number */
u8 sensi_level; /* GPIO sensitive level. */
};
/*
* Power supply via control GPIO.
*/
#define POWER_VIA_GPIO 1 /* */
#define POWER_GPIO_MUTEX 1 /* 1 - GPIO is a io mutexed IO */
#define POWER_GPIO_MUTEX_NAME GPIOH6_IQ_SEL_NAME
#define POWER_GPIO_MUTEXT_VAL IOMUXB_GPIO1_D6
#define POWER_GPIO_ID GPIOPortH_Pin6
#define POWER_LEVEL_SENSITIVE GPIO_HIGH
int wifi_turn_on_card(void);
int wifi_turn_off_card(void);
int wifi_power_up_wifi(void);
int wifi_power_down_wifi(void);
int wifi_power_reset(void);
#endif /* WIFI_GPIO_POWER_CONTROL */
#endif /* WIFI_POWER_H */

View File

@@ -3,6 +3,7 @@
#include <linux/module.h>
extern void if_sdio_init_module2(void);
extern void if_sdio_exit_module(void);
static int wlan_init_module(void)
{
@@ -12,6 +13,12 @@ static int wlan_init_module(void)
return 0;
}
module_init(wlan_init_module);
static int wlan_exit_module(void)
{
printk("move wlan driver..........\n");
if_sdio_exit_module();
//module_exit(wlan_exit_module);
return 0;
}
module_init(wlan_init_module);
module_exit(wlan_exit_module);