M7350/wlan/8192es/DriverSrcPkg/Driver/rtl8192cd_92es/8192cd_pwrctrl.c
2024-09-09 08:59:52 +00:00

770 lines
20 KiB
C
Executable File

#ifdef CONFIG_POWER_SAVE
#define _8192CD_PWRCTRL_C_
#include <linux/irq.h>
#include <linux/gpio.h>
#ifdef CONFIG_WAKELOCK
#include <linux/wakelock.h>
#endif
#include "8192cd_headers.h"
#include "8192cd_debug.h"
#include "8192cd_pwrctrl.h"
#ifdef PLATFORM_ARM_BALONG
#include <linux/platform_device.h>
#endif
#ifdef USE_WAKELOCK_MECHANISM
static struct wakeup_source *ws_wifi;
#endif
u16 temp_608;
int rtw_sdio_prepare(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct net_device *netdev = sdio_get_drvdata(func);
struct rtl8192cd_priv *priv = GET_DEV_PRIV(netdev);
struct priv_shared_info *pshare = priv->pshare;
if (!IS_DRV_OPEN(priv)) {
DEBUG_INFO("[%s] driver closed, return.\n", __FUNCTION__);
return 0;
}
// check tx pending queue is empty.
if (pshare->pending_xmitbuf_queue.qlen) {
DEBUG_INFO("[%s] tx pending queue not empty.\n", __FUNCTION__);
rtw_lock_suspend_timeout(priv, 2*priv->pmib->dot11OperationEntry.ps_timeout);
return -1;
}
if (GET_HAL_INTF_DATA(priv)->SdioTxIntStatus) {
DEBUG_INFO("[%s] SdioTxIntStatus is not idle.\n", __FUNCTION__);
rtw_lock_suspend_timeout(priv, 2*priv->pmib->dot11OperationEntry.ps_timeout);
return -1;
}
RTL_W8(0x286, RTL_R8(0x286)|BIT2);
if (RTL_R8(0x286) & BIT1) {
DEBUG_INFO("[%s] rx dma is idle.\n", __FUNCTION__);
} else {
DEBUG_INFO("[%s] rx dma is not idle.\n", __FUNCTION__);
}
pshare->ps_xfer_seq = pshare->xfer_seq;
return 0;
}
void rtw_sdio_complete(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct net_device *netdev = sdio_get_drvdata(func);
struct rtl8192cd_priv *priv = GET_DEV_PRIV(netdev);
if (!IS_DRV_OPEN(priv)) {
DEBUG_INFO("[%s] driver closed, return.\n", __FUNCTION__);
return;
}
RTL_W8(0x286 , (RTL_R8(0x286) & (~BIT2)));
}
int rtw_sdio_suspend(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct net_device *netdev = sdio_get_drvdata(func);
struct rtl8192cd_priv *priv = GET_DEV_PRIV(netdev);
struct priv_shared_info *pshare = priv->pshare;
struct ap_pwrctrl_priv *ps_handle = &pshare->ap_ps_handle;
unsigned char loc_bcn[3] = {0};
unsigned char loc_probe[3] = {0};
unsigned int i, hidden, wait_cnt = 0;
u1Byte IsLinked = 0;
int err = -1;
_irqL irqL;
if (!IS_DRV_OPEN(priv)) {
DEBUG_INFO("[%s] driver closed, return.\n", __FUNCTION__);
#ifdef USE_WAKELOCK_MECHANISM
mmc_pm_flag_t pm_flag = 0;
pm_flag = sdio_get_host_pm_caps(func);
pm_flag |= MMC_PM_KEEP_POWER;
sdio_set_host_pm_flags(func, pm_flag);
DEBUG_INFO("[%s] driver closed, but need keep wifi power.\n", __FUNCTION__);
#endif
return 0;
}
if (pshare->offload_prohibited) {
DEBUG_ERR("[%s] power save disabled ,return\n", __FUNCTION__);
pshare->offload_function_ctrl = RTW_PM_AWAKE;
#ifdef USE_WAKELOCK_MECHANISM
rtw_lock_suspend(priv);
RTL_W8(0x286 , (RTL_R8(0x286) & (~BIT2)));
#endif
return -1;
}
_enter_critical_mutex(&pshare->apps_lock, &irqL);
if (RTW_PM_SUSPEND == pshare->offload_function_ctrl) {
_exit_critical_mutex(&pshare->apps_lock, &irqL);
return 0;
}
DEBUG_INFO("%s ===>\n", __FUNCTION__);
DEBUG_INFO("[%s,%d] name = %s\n", __FUNCTION__, __LINE__, priv->dev->name);
DEBUG_INFO("[%s,%d] ps_level = %d\n", __FUNCTION__, __LINE__, priv->pmib->dot11OperationEntry.ps_level);
DEBUG_INFO("[%s,%d] ps_timeout = %d\n", __FUNCTION__, __LINE__, priv->pmib->dot11OperationEntry.ps_timeout);
DEBUG_INFO("[%s] total_assoc_num=%d\n", __FUNCTION__, pshare->total_assoc_num);
temp_608 = RTL_R16(0x608);
RTL_W16(0x608, ((temp_608|BIT7)&0xfcff));
#ifdef CONFIG_RTL_88E_SUPPORT
if (pshare->total_assoc_num)
RTL8188E_SuspendTxReport(priv);
#endif
if (timer_pending(&pshare->beacon_timer))
del_timer_sync(&pshare->beacon_timer);
if (timer_pending(&pshare->ps_timer))
del_timer_sync(&pshare->ps_timer);
if (timer_pending(&pshare->xmit_check_timer))
del_timer_sync(&pshare->xmit_check_timer);
pshare->ps_timer_expires = 0;
/* start beacon offload */
#ifdef USE_WAKELOCK_MECHANISM
if (pshare->offload_function_ctrl == RTW_PM_AWAKE)
{
pshare->offload_function_ctrl = RTW_PM_PREPROCESS;
pshare->ps_ctrl = RTW_ACT_POWERDOWN;
update_beacon(pshare->bcn_priv[0]);
pshare->ps_ctrl = RTW_ACT_POWERON;
}
#endif
#if defined(CONFIG_RTL_88E_SUPPORT)
loc_bcn[0] = TX_TOTAL_PAGE_NUMBER_88E + 1;
loc_probe[0] = loc_bcn[0] + pshare->ap_offload_res[0].probe_offset;
#elif defined(CONFIG_WLAN_HAL_8192EE)
loc_bcn[0] = 0xf6;
loc_probe[0] = loc_bcn[0] + pshare->ap_offload_res[0].probe_offset;
#endif
hidden = 0;
if (pshare->bcn_priv[0]->pmib->dot11OperationEntry.hiddenAP)
hidden |= BIT0;
#ifdef MBSSID
for (i = 1; i < pshare->nr_bcn; i++) {
loc_bcn[i] = loc_bcn[0] + pshare->ap_offload_res[i].beacon_offset;
loc_probe[i] = loc_bcn[0] + pshare->ap_offload_res[i].probe_offset;
if (pshare->bcn_priv[i]->pmib->dot11OperationEntry.hiddenAP)
hidden |= BIT(i);
}
DEBUG_INFO("clif loc: bcn[0]=%x probe[0]=%x bcn[1]=%x probe[1]=%x, hidden=%x\n",
loc_bcn[0], loc_probe[0], loc_bcn[1], loc_probe[1], hidden);
#else
DEBUG_INFO("clif loc: bcn[0]=%x probe[0]=%x, hidden=%x\n",
loc_bcn[0], loc_probe[0], hidden);
#endif
DEBUG_INFO("[%s] total tx bcn inrerface : %d\n", __FUNCTION__, pshare->nr_bcn);
#ifdef PLATFORM_ARM_BALONG
if (pshare->wake_irq > 0)
enable_irq_wake(pshare->wake_irq);
#endif
#ifdef CONFIG_WLAN_HAL_8192EE
RTL_W8(0x1c , (RTL_R8(0x1c) & (~(BIT1|BIT0))));
#endif
//stop rx
RTL_W8(0x286, RTL_R8(0x286)|BIT2);
//polling rx dma idle
while (!(RTL_R8(0x286) & BIT1)) {
if (++wait_cnt > 100 || pshare->ps_ctrl == RTW_ACT_POWERON)
{
DEBUG_INFO("[%s] rx dma is not idle.\n", __FUNCTION__);
goto fail;
}
msleep(1);
}
DEBUG_INFO("[%s] rx dma is idle.\n", __FUNCTION__);
DisableSdioInterrupt( priv);
ClearSdioInterrupt(priv);
ps_handle->suspend_processing = 1;
if (pshare->total_assoc_num > 0)
IsLinked = 1;
DEBUG_INFO("[%s,%d] IsLinked = %x, hidAP = %x\n", __FUNCTION__, __LINE__, IsLinked, hidden);
DEBUG_INFO("[%s,%d] offload duration = %d us\n", __FUNCTION__, __LINE__, OFFLOAD_DURATION);
DEBUG_INFO("[%s,%d] Repeat trigger duration = %d %s\n", __FUNCTION__, __LINE__,
REPEAT_TRIGGER_DURATION * ((REPEAT_TRIGGER_UNIT==TRIGGER_TIME_2SEC)?2:8),
(REPEAT_TRIGGER_UNIT==TRIGGER_TIME_2SEC)?"sec":"msec");
RTL_W8(0x1c7, 0x0); //check send pulse or not.
pshare->pwr_state = RTW_STS_SUSPEND;
pshare->offload_function_ctrl = RTW_PM_SUSPEND;
pshare->ap_ps_handle.en_32k = (priv->pmib->dot11OperationEntry.ps_32k_en ? 1:0);
rtw_ap_start_fw_ps(priv, pshare->ap_ps_handle.en_32k, 1);
delay_us(10);
#if defined(CONFIG_RTL_88E_SUPPORT)
set_wakeup_pin(priv, PULSE_DURATION, 1, 1, 1, 7);
delay_us(10);
//set_repeat_wake_pulse(priv, 1, REPEAT_TRIGGER_UNIT, REPEAT_TRIGGER_DURATION);
//delay_us(10);
set_bcn_resv_page(priv, loc_bcn[0], loc_bcn[1], loc_bcn[2]);
delay_us(10);
set_probe_res_resv_page(priv, loc_probe[0], loc_probe[1], loc_probe[2]);
delay_us(10);
set_ap_offload(priv, 0, hidden, 1, IsLinked);
#elif defined(CONFIG_WLAN_HAL_8192EE)
GET_HAL_INTERFACE(priv)->SetAPOffloadHandler(priv, 1, IsLinked,
pshare->nr_bcn, hidden, 0, loc_bcn, loc_probe);
#endif
delay_us(10);
ps_handle->h2c_done = 1;
wait_cnt = 0;
// check firmware is receive H2C command for AP offload
while (!(RTL_R8(0x130)&BIT3))
{
if (++wait_cnt > 20) {
DEBUG_ERR("[%s] firmware no receive H2C command or already leave AP offload mode! \n", __FUNCTION__);
goto fail;
}
delay_ms(1);
}
if (pshare->ap_ps_handle.en_32k)
set_ap_32k(priv, 1);
#ifdef USE_WAKELOCK_MECHANISM
mmc_pm_flag_t pm_flag = 0;
pm_flag = sdio_get_host_pm_caps(func);
if (!(pm_flag & MMC_PM_KEEP_POWER)) {
DEBUG_ERR("%s: cannot remain alive while host is suspended\n", sdio_func_id(func));
err = -ENOSYS;
goto fail;
}
DEBUG_INFO("cmd: suspend with MMC_PM_KEEP_POWER\n");
pm_flag |= MMC_PM_KEEP_POWER;
sdio_set_host_pm_flags(func, pm_flag);
#endif
if (pshare->ps_xfer_seq != pshare->xfer_seq) {
DEBUG_INFO("[%s] Detect traffic.\n", __FUNCTION__);
goto fail;
}
#ifdef PLATFORM_ARM_BALONG
extern int BSP_PWRCTRL_WIFI_LowPowerEnter(void);
BSP_PWRCTRL_WIFI_LowPowerEnter();
#endif
DEBUG_INFO("<=== %s\n", __FUNCTION__);
_exit_critical_mutex(&pshare->apps_lock, &irqL);
return 0;
fail:
pshare->offload_function_ctrl = RTW_PM_SUSPEND;
__rtw_sdio_resume(priv);
_exit_critical_mutex(&pshare->apps_lock, &irqL);
return err;
}
int __rtw_sdio_resume(struct rtl8192cd_priv *priv)
{
struct priv_shared_info *pshare = priv->pshare;
struct ap_pwrctrl_priv *ps_handle = &pshare->ap_ps_handle;
int i, wait_cnt = 0;
// Don't do AP offload exit when not in AP offload state. otherwise it may cause TXDMA error.
if (RTW_PM_SUSPEND != pshare->offload_function_ctrl)
return 0;
DEBUG_INFO("%s ===>\n", __FUNCTION__);
if (priv->pmib->dot11OperationEntry.ps_level < 2 && pshare->total_assoc_num > 0)
{
DEBUG_ERR("[%s] current power save not match linked ps!\n", __FUNCTION__);
}
#ifdef PLATFORM_ARM_BALONG
if (pshare->wake_irq > 0)
disable_irq_wake(pshare->wake_irq);
#endif
// Don't do H2C commands to exit AP offload during error recovery when H2C command which enable AP offload is not done.
// Otherwise it will cause TXDMA error 0x14.
if (ps_handle->h2c_done) {
ps_handle->h2c_done = 0;
if (pshare->ap_ps_handle.en_32k) {
set_ap_32k(priv, 0);
delay_ms(1);
}
#if defined(CONFIG_RTL_88E_SUPPORT)
set_ap_offload(priv, 0, 0, 0, 0);
#elif defined(CONFIG_WLAN_HAL_8192EE)
GET_HAL_INTERFACE(priv)->SetAPOffloadHandler(priv, 0, 0, 0, 0, 0, 0, 0);
#endif
delay_ms(1);
rtw_ap_stop_fw_ps(priv);
#ifdef CONFIG_RTL_88E_SUPPORT
RTL_W8(REG_MBID_NUM, RTL_R8(REG_MBID_NUM)& (~BIT(3)));
#endif
// check firmware is leave AP offload mode
while ((RTL_R8(0x130)&BIT3))
{
if (++wait_cnt > 20) {
DEBUG_ERR("[%s] firmware no leave AP offload mode! \n", __FUNCTION__);
break;
}
delay_ms(1);
}
}
RTL_W8(0x286 , (RTL_R8(0x286) & (~BIT2)));
for (i=0; i<10; i++)
{
if(RTL_R8(0x286)&BIT2)
{
DEBUG_ERR("[%s] resume 0x286 clear BIT2 fail\n", __FUNCTION__);
RTL_W8(0x286 , (RTL_R8(0x286) & (~BIT2)));
delay_ms(1);
}
else
break;
}
ps_handle->suspend_processing = 0;
RTL_W16(0x608,temp_608);
#ifdef CONFIG_RTL_88E_SUPPORT
if (pshare->total_assoc_num)
RTL8188E_ResumeTxReport(priv);
#endif
// Update current Tx FIFO page & Tx OQT space
WARN_ON(GET_HAL_INTF_DATA(priv)->SdioTxIntStatus);
sdio_query_txbuf_status(priv);
sdio_query_txoqt_status(priv);
pshare->offload_function_ctrl = RTW_PM_AWAKE;
pshare->pwr_state = RTW_STS_NORMAL;
pshare->ps_ctrl = RTW_ACT_IDLE;
if (priv->drv_state & DRV_STATE_OPEN) {
rtw_offload_reinit_timer(priv);
rtw_lock_suspend_timeout(priv, 2*priv->pmib->dot11OperationEntry.ps_timeout);
}
// Interrupt enable must be last step of the resume to avoid interfering with resume process.
EnableSdioInterrupt(priv);
DEBUG_INFO("<=== %s\n", __FUNCTION__);
return 0;
}
int rtw_sdio_resume(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct net_device *netdev = sdio_get_drvdata(func);
struct rtl8192cd_priv *priv;
int err = 0;
_irqL irqL;
if (NULL == netdev)
return 0;
priv = GET_DEV_PRIV(netdev);
if (!IS_DRV_OPEN(priv)) {
DEBUG_INFO("[%s] driver closed, return.\n", __FUNCTION__);
return 0;
}
_enter_critical_mutex(&priv->pshare->apps_lock, &irqL);
err = __rtw_sdio_resume(priv);
_exit_critical_mutex(&priv->pshare->apps_lock, &irqL);
return err;
}
/********************************************************/
#ifdef PLATFORM_ARM_BALONG
#include <linux/irq.h>
enum {
GPIO_NORMAL=0,
GPIO_INTERRUPT=0,
};
#define GPIO_MAXIMUM (12)
#define GPIO_MAX_PINS (8)
#define BALONG_GPIO_0(_nr) (_nr)
#define BALONG_GPIO_1(_nr) (BALONG_GPIO_0(GPIO_MAX_PINS - 1) + (_nr) + 1 )
#define BALONG_GPIO_2(_nr) (BALONG_GPIO_1(GPIO_MAX_PINS - 1) + (_nr) + 1 )
#define BALONG_GPIO_3(_nr) (BALONG_GPIO_2(GPIO_MAX_PINS - 1) + (_nr) + 1 )
#define BALONG_GPIO_4(_nr) (BALONG_GPIO_3(GPIO_MAX_PINS - 1) + (_nr) + 1 )
#define BALONG_GPIO_5(_nr) (BALONG_GPIO_4(GPIO_MAX_PINS - 1) + (_nr) + 1 )
#define BALONG_GPIO_6(_nr) (BALONG_GPIO_5(GPIO_MAX_PINS - 1) + (_nr) + 1 )
#define BALONG_GPIO_7(_nr) (BALONG_GPIO_6(GPIO_MAX_PINS - 1) + (_nr) + 1 )
#define INT_GPIO_GP5 117
#define BALONG_GPIO_WIFI_WAKEUP_CHIP 5
//#define BALONG_GPIO_WIFI_WAKEUP_PIN 4
#define BALONG_GPIO_WIFI_WAKEUP_PIN 0
#define BALONG_GPIO_WIFI_WAKEUP BALONG_GPIO_5(BALONG_GPIO_WIFI_WAKEUP_PIN)
#define BALONG_GPIO_WIFI_PWR_PIN 2
#define BALONG_GPIO_WIFI_PWR BALONG_GPIO_5(BALONG_GPIO_WIFI_PWR_PIN)
/*defined in drivers/mmc/host/hisdio_sys_ctrl.h */
#define BALONG_GPIO_WIFI_RESET_PIN 6
#define BALONG_GPIO_WIFI_RESET BALONG_GPIO_5(BALONG_GPIO_WIFI_RESET_PIN)
extern int gpio_int_mask_set(unsigned int gpio);
extern int gpio_int_state_clear(unsigned int gpio);
extern int gpio_set_function(unsigned int gpio, unsigned function);
extern int gpio_int_trigger_set(unsigned int gpio, unsigned int trigger);
extern int gpio_int_unmask_set(unsigned int gpio);
extern int gpio_int_state_get(unsigned int gpio, unsigned *state);
extern int gpio_direction_input(unsigned int gpio);
extern int gpio_request(unsigned int gpio, const char *lebel);
extern void gpio_free(unsigned int gpio);
extern int gpio_direction_output(unsigned int gpio, int value);
extern void balong_wifi_vote(int element);
extern void balong_wifi_devote(int element);
#ifdef __LINUX_2_6__
irqreturn_t balong_gpio_wakeup_isr(int irq, void *dev_instance)
#else
void balong_gpio_wakeup_isr(int irq, void *dev_instance, struct pt_regs *regs)
#endif
{
struct net_device *dev = NULL;
struct rtl8192cd_priv *priv = NULL;
unsigned int ucData;
priv =(struct rtl8192cd_priv *) dev_instance;
gpio_int_state_get(BALONG_GPIO_WIFI_WAKEUP, (unsigned int*)&ucData);
printk("acli: get intr %d\n", ucData);
if ( !ucData )
return IRQ_NONE;
gpio_int_state_clear(BALONG_GPIO_WIFI_WAKEUP);
if ( priv->pshare->pwr_state == RTW_STS_SUSPEND ) {
DEBUG_INFO("[%s,%d] RTW_STS_SUSPEND\n", __FUNCTION__, __LINE__);
priv->pshare->pwr_state = RTW_STS_NORMAL;
priv->pshare->ps_ctrl = RTW_ACT_IDLE;
schedule_work(&priv->ap_cmd_queue);
}
return IRQ_HANDLED;
}
int set_balong_wakeup_pin(struct net_device *dev, struct rtl8192cd_priv *priv)
{
int rc;
int gpio_num =7;
RTL_W32(GPIO_PIN_CTRL, RTL_R32(GPIO_PIN_CTRL) & ~BIT(gpio_num+8));
msleep(10);
gpio_int_mask_set(BALONG_GPIO_WIFI_WAKEUP);
gpio_int_state_clear(BALONG_GPIO_WIFI_WAKEUP);
// gpio_set_function(BALONG_GPIO_WIFI_WAKEUP);
gpio_set_function(BALONG_GPIO_WIFI_WAKEUP, GPIO_INTERRUPT);
gpio_int_trigger_set(BALONG_GPIO_WIFI_WAKEUP, IRQ_TYPE_EDGE_RISING);
gpio_int_state_clear(BALONG_GPIO_WIFI_WAKEUP);
gpio_int_unmask_set(BALONG_GPIO_WIFI_WAKEUP);
dev->irq = INT_GPIO_GP5;
priv->pshare->wake_irq = dev->irq;
rc = request_irq(dev->irq, balong_gpio_wakeup_isr, IRQF_SHARED, dev->name, priv);
if ( rc )
{
printk("some issue in wake-up irq, rx=%d\n", rc);
return -1;
}
gpio_int_state_clear(BALONG_GPIO_WIFI_WAKEUP);
gpio_int_unmask_set(BALONG_GPIO_WIFI_WAKEUP);
return 0;
}
#endif // PLATFORM_ARM_BALONG
/********************************************************/
int init_wifi_wakeup_gpio(struct net_device *dev, struct rtl8192cd_priv *priv)
{
int err = 0;
DEBUG_INFO("[%s] ENTRY \n", __FUNCTION__);
#ifdef PLATFORM_ARM_BALONG
err = set_balong_wakeup_pin(dev, priv);
#endif
return err;
}
void free_wifi_wakeup_gpio(struct net_device *dev, struct rtl8192cd_priv *priv)
{
DEBUG_INFO("[%s] ENTRY \n", __FUNCTION__);
#ifdef PLATFORM_ARM_BALONG
gpio_free(BALONG_GPIO_WIFI_WAKEUP_PIN);
#endif
}
#define RTW_SUSPEND_LOCK_NAME "rtw_wifi"
#ifdef USE_WAKELOCK_MECHANISM
#ifdef CONFIG_WAKELOCK
static struct wake_lock rtw_suspend_lock;
#endif
#endif
void rtw_suspend_lock_init(void)
{
PRINT_INFO("[%s] ENTRY \n", __FUNCTION__);
#ifdef USE_WAKELOCK_MECHANISM
#ifdef CONFIG_WAKELOCK
wake_lock_init(&rtw_suspend_lock, WAKE_LOCK_SUSPEND, RTW_SUSPEND_LOCK_NAME);
#elif defined(CONFIG_PM_WAKELOCKS)
ws_wifi = wakeup_source_register("rtl8192 wake");
#endif
#endif
}
void rtw_suspend_lock_deinit(void)
{
PRINT_INFO("[%s] ENTRY \n", __FUNCTION__);
#ifdef USE_WAKELOCK_MECHANISM
#ifdef CONFIG_WAKELOCK
wake_lock_destroy(&rtw_suspend_lock);
#elif defined(CONFIG_PM_WAKELOCKS)
wakeup_source_unregister(ws_wifi);
#endif
#endif
}
void rtw_lock_suspend(struct rtl8192cd_priv *priv)
{
PRINT_INFO("[%s] ENTRY \n", __FUNCTION__);
#ifdef USE_WAKELOCK_MECHANISM
#ifdef CONFIG_WAKELOCK
wake_lock(&rtw_suspend_lock);
#elif defined(CONFIG_PM_WAKELOCKS)
__pm_stay_awake(ws_wifi);
#endif
#endif
}
void rtw_unlock_suspend(struct rtl8192cd_priv *priv)
{
PRINT_INFO("[%s] ENTRY \n", __FUNCTION__);
#ifdef USE_WAKELOCK_MECHANISM
#ifdef CONFIG_WAKELOCK
wake_unlock(&rtw_suspend_lock);
#elif defined(CONFIG_PM_WAKELOCKS)
__pm_relax(ws_wifi);
#endif
#endif
}
void rtw_lock_suspend_timeout(struct rtl8192cd_priv *priv, unsigned int timeout)
{
unsigned long expires;
_irqL irqL;
if (priv->pshare->offload_prohibited)
return;
if (!IS_DRV_OPEN(GET_ROOT(priv)))
return;
PRINT_INFO("[%s] ENTRY TO %d\n" , __FUNCTION__, timeout);
#ifdef USE_WAKELOCK_MECHANISM
#ifdef CONFIG_WAKELOCK
wake_lock_timeout(&rtw_suspend_lock, timeout);
#elif defined(CONFIG_PM_WAKELOCKS)
__pm_wakeup_event(ws_wifi, timeout);
#endif
timeout = timeout + 1000;
#endif
_enter_critical(&priv->pshare->offload_lock, &irqL);
if (!timeout) {
del_timer(&priv->pshare->ps_timer);
priv->pshare->ps_timer_expires = 0;
goto unlock;
}
expires = jiffies + RTL_MILISECONDS_TO_JIFFIES(timeout);
if (!priv->pshare->ps_timer_expires || time_after(expires, priv->pshare->ps_timer_expires)) {
mod_timer(&priv->pshare->ps_timer, expires);
priv->pshare->ps_timer_expires = expires;
}
unlock:
_exit_critical(&priv->pshare->offload_lock, &irqL);
}
int rtw_ap_ps_xmit_monitor(struct rtl8192cd_priv *priv)
{
if (0 == priv->assoc_num) {
//printk("[%s,%d] Detects have traffic and no STA link, drop the packet.\n", __FUNCTION__, __LINE__);
return 1;
}
priv->pshare->xfer_seq++;
if (RTW_PM_SUSPEND == priv->pshare->offload_function_ctrl) {
if (RTW_STS_SUSPEND == priv->pshare->pwr_state) {
//printk("[%s,%d] Detects have traffic sent to STA.\n", __FUNCTION__, __LINE__);
priv->pshare->pwr_state = RTW_STS_NORMAL;
priv->pshare->ps_ctrl = RTW_ACT_IDLE;
schedule_work(&GET_ROOT(priv)->ap_cmd_queue);
}
//printk("[%s,%d] Entry queue.\n", __FUNCTION__, __LINE__);
} else {
rtw_lock_suspend_timeout(priv, 2*GET_ROOT(priv)->pmib->dot11OperationEntry.ps_timeout);
}
return 0;
}
void rtw_ap_ps_recv_monitor(struct rtl8192cd_priv *priv)
{
rtw_lock_suspend_timeout(priv, 2*GET_ROOT(priv)->pmib->dot11OperationEntry.ps_timeout);
}
void rtw_ap_ps_init(struct rtl8192cd_priv *priv)
{
DEBUG_INFO("[%s] ENTRY \n", __FUNCTION__);
priv->pshare->ap_ps_handle.h2c_done = 0;
priv->pshare->ap_ps_handle.sleep_time = 0;
priv->pshare->ap_ps_handle.suspend_processing = 0;
}
void rtw_ap_ps_deinit(struct rtl8192cd_priv *priv)
{
DEBUG_INFO("[%s] ENTRY \n", __FUNCTION__);
}
void rtw_ap_stop_fw_ps(struct rtl8192cd_priv *priv)
{
DEBUG_INFO("[%s] ENTRY \n", __FUNCTION__);
#if defined(CONFIG_RTL_88E_SUPPORT)
set_softap_ps(priv, 0, 0, 0, 0);
#elif defined(CONFIG_WLAN_HAL_8192EE)
/* Set H2C Cmd to FW To leave PS */
GET_HAL_INTERFACE(priv)->SetSAPPsHandler(priv, 0, 0, 0, 0); //zyj test
#endif
}
void rtw_ap_start_fw_ps(struct rtl8192cd_priv *priv, u4Byte en_32k, u4Byte reason)
{
u1Byte sleep_time;
u1Byte beaconInterval = priv->pmib->dot11StationConfigEntry.dot11BeaconPeriod;
int ps_sleep_time = priv->pmib->dot11OperationEntry.ps_sleep_time;
DEBUG_INFO("[%s] ENTRY \n", __FUNCTION__);
/* Set H2C Cmd to FW To enter PS */
switch (priv->pshare->nr_bcn) {
case 2:
sleep_time = 20;//35
break;
case 3:
sleep_time = 20;
break;
default:
sleep_time = 20;
break;
}
if (ps_sleep_time != 0)
sleep_time = ps_sleep_time;
priv->pshare->ap_ps_handle.sleep_time = sleep_time;
sleep_time = (sleep_time * beaconInterval) / 100;
DEBUG_INFO("[%s] sleep_time = %d\n", __FUNCTION__, sleep_time);
#if defined(CONFIG_RTL_88E_SUPPORT)
set_softap_ps(priv, 1, en_32k, 1, sleep_time);
#elif defined(CONFIG_WLAN_HAL_8192EE)
GET_HAL_INTERFACE(priv)->SetSAPPsHandler(priv, 1, en_32k, 1, sleep_time);
#endif
}
void sdio_power_save_timer(unsigned long task_priv)
{
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
struct priv_shared_info *pshare = priv->pshare;
if (pshare->offload_prohibited)
return;
if (pshare->pending_xmitbuf_queue.qlen || (pshare->nr_bcn > 3)) {
rtw_lock_suspend_timeout(priv, 2*priv->pmib->dot11OperationEntry.ps_timeout);
return;
}
DEBUG_INFO("[%s] ENTRY \n", __FUNCTION__);
if (RTW_PM_AWAKE == pshare->offload_function_ctrl) {
pshare->offload_function_ctrl = RTW_PM_PREPROCESS;
pshare->ps_xfer_seq = pshare->xfer_seq;
}
}
#endif // CONFIG_POWER_SAVE