Loquate: Add bt sleep and wakeup host function

This commit is contained in:
wdc
2012-05-25 18:13:16 +08:00
parent 8c1ec65410
commit de451c76c8
2 changed files with 225 additions and 98 deletions

View File

@@ -176,6 +176,7 @@ CONFIG_BT_HIDP=y
CONFIG_BT_HCIUART=y
CONFIG_BT_HCIUART_H4=y
CONFIG_BT_HCIBCM4325=y
CONFIG_BT_AUTOSLEEP=y
CONFIG_RFKILL=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y

View File

@@ -24,14 +24,87 @@
#include <mach/iomux.h>
#include <linux/wakelock.h>
#include <linux/timer.h>
#include <mach/board.h>
#if 0
#define DBG(x...) printk(KERN_INFO x)
#define DBG(x...) printk(KERN_INFO "[BT_RFKILL]: "x)
#else
#define DBG(x...)
#endif
#define BT_WAKE_HOST_SUPPORT 1
#define LOG(x...) printk(KERN_INFO "[BT_RFKILL]: "x)
#ifdef CONFIG_BCM4329
#define WIFI_BT_POWER_TOGGLE 1
#else
#define WIFI_BT_POWER_TOGGLE 0
#endif
#define BT_WAKE_LOCK_TIMEOUT 10 //s
#define BT_AUTO_SLEEP_TIMEOUT 3
/*
* IO Configuration for RK29
*/
#ifdef CONFIG_ARCH_RK29
#define BT_WAKE_HOST_SUPPORT 0
/* IO configuration */
// BT power pin
#define BT_GPIO_POWER RK29_PIN5_PD6
#define IOMUX_BT_GPIO_POWER() rk29_mux_api_set(GPIO5D6_SDMMC1PWREN_NAME, GPIO5H_GPIO5D6);
// BT reset pin
#define BT_GPIO_RESET RK29_PIN6_PC4
#define IOMUX_BT_GPIO_RESET()
// BT wakeup pin
#define BT_GPIO_WAKE_UP RK29_PIN6_PC5
#define IOMUX_BT_GPIO_WAKE_UP()
// BT wakeup host pin
#define BT_GPIO_WAKE_UP_HOST
#define IOMUX_BT_GPIO_WAKE_UP_HOST()
//bt cts paired to uart rts
#define UART_RTS RK29_PIN2_PA7
#define IOMUX_UART_RTS_GPIO() rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_GPIO2A7)
#define IOMUX_UART_RTS() rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_UART2_RTS_N)
/*
* IO Configuration for RK30
*/
#elif defined (CONFIG_ARCH_RK30)
#define BT_WAKE_HOST_SUPPORT 1
/* IO configuration */
// BT power pin
#define BT_GPIO_POWER RK30_PIN4_PD5
#define IOMUX_BT_GPIO_POWER rk30_mux_api_set(GPIO4D5_SMCDATA13_TRACEDATA13_NAME, GPIO4D_GPIO4D5)
// BT reset pin
#define BT_GPIO_RESET RK30_PIN3_PD1
#define IOMUX_BT_GPIO_RESET rk30_mux_api_set(GPIO3D1_SDMMC1BACKENDPWR_NAME, GPIO3D_GPIO3D1)
// BT wakeup pin
#define BT_GPIO_WAKE_UP RK30_PIN3_PC6
#define IOMUX_BT_GPIO_WAKE_UP() rk29_mux_api_set(GPIO3C6_SDMMC1DETECTN_NAME, GPIO3C_GPIO3C6);
// BT wakeup host pin
#define BT_GPIO_WAKE_UP_HOST RK30_PIN3_PD2
#define IOMUX_BT_GPIO_WAKE_UP_HOST() rk29_mux_api_set(GPIO3D2_SDMMC1INTN_NAME, GPIO3D_GPIO3D2)
#define BT_IRQ_WAKE_UP_HOST gpio_to_irq(BT_GPIO_WAKE_UP_HOST)
//bt cts paired to uart rts
#define UART_RTS RK30_PIN1_PA3
#define IOMUX_UART_RTS_GPIO() rk29_mux_api_set(GPIO1A3_UART0RTSN_NAME, GPIO1A_GPIO1A3)
#define IOMUX_UART_RTS() rk29_mux_api_set(GPIO1A3_UART0RTSN_NAME, GPIO1A_UART0_RTS_N)
#endif
struct bt_ctrl
{
@@ -43,25 +116,13 @@ struct bt_ctrl
#endif
};
#define BT_GPIO_POWER RK30_PIN4_PD5
#define IOMUX_BT_GPIO_POWER rk29_mux_api_set(GPIO4D5_SMCDATA13_TRACEDATA13_NAME, GPIO4D_GPIO4D5);
#define BT_GPIO_RESET RK30_PIN3_PD1
#define IOMUX_BT_GPIO_RESET rk29_mux_api_set(GPIO3D1_SDMMC1BACKENDPWR_NAME, GPIO3D_GPIO3D1);
#ifdef CONFIG_BT_HCIBCM4325
#define BT_GPIO_WAKE_UP RK30_PIN3_PC6
#endif
#if BT_WAKE_HOST_SUPPORT
#define BT_GPIO_WAKE_UP_HOST RK30_PIN3_PD2
#define IOMUX_BT_GPIO_WAKE_UP_HOST() rk29_mux_api_set(GPIO3D2_SDMMC1INTN_NAME, GPIO3D_GPIO3D2);
#define BT_WAKE_LOCK_TIMEOUT 10 //s
#endif
static const char bt_name[] =
#if defined(CONFIG_RKWIFI)
"rk903"
#if defined(CONFIG_RKWIFI_26M)
"rk903_26M"
#else
"rk903"
#endif
#elif defined(CONFIG_BCM4329)
"bcm4329"
#elif defined(CONFIG_MV8787)
@@ -71,11 +132,15 @@ static const char bt_name[] =
#endif
;
#if WIFI_BT_POWER_TOGGLE
extern int rk29sdk_bt_power_state;
extern int rk29sdk_wifi_power_state;
#endif
struct bt_ctrl gBtCtrl;
struct timer_list bt_sleep_tl;
#if BT_WAKE_HOST_SUPPORT
void resetBtHostSleepTimer(void)
{
@@ -85,7 +150,7 @@ void resetBtHostSleepTimer(void)
void btWakeupHostLock(void)
{
if(gBtCtrl.b_HostWake == false){
DBG("*************************Lock\n");
DBG("** Lock **\n");
wake_lock(&(gBtCtrl.bt_wakelock));
gBtCtrl.b_HostWake = true;
}
@@ -94,7 +159,7 @@ void btWakeupHostLock(void)
void btWakeupHostUnlock(void)
{
if(gBtCtrl.b_HostWake == true){
DBG("*************************UnLock\n");
DBG("** UnLock **\n");
wake_unlock(&(gBtCtrl.bt_wakelock)); //<2F><>ϵͳ˯<CDB3><CBAF>
gBtCtrl.b_HostWake = false;
}
@@ -102,23 +167,83 @@ void btWakeupHostUnlock(void)
static void timer_hostSleep(unsigned long arg)
{
DBG("%s---b_HostWake=%d\n",__FUNCTION__,gBtCtrl.b_HostWake);
DBG("b_HostWake=%d\n", gBtCtrl.b_HostWake);
btWakeupHostUnlock();
}
void bcm4325_sleep(unsigned long bSleep);
#ifdef CONFIG_PM
static irqreturn_t bcm4329_wake_host_irq(int irq, void *dev)
{
DBG("%s\n",__FUNCTION__);
btWakeupHostLock();
resetBtHostSleepTimer();
return IRQ_HANDLED;
}
static void rfkill_do_wakeup(struct work_struct *work)
{
// disable bt wakeup host
DBG("** free irq\n");
free_irq(BT_IRQ_WAKE_UP_HOST, NULL);
DBG("Enable UART_RTS\n");
gpio_set_value(UART_RTS, GPIO_LOW);
IOMUX_UART_RTS();
}
static DECLARE_DELAYED_WORK(wakeup_work, rfkill_do_wakeup);
static int bcm4329_rfkill_suspend(struct platform_device *pdev, pm_message_t state)
{
DBG("%s\n",__FUNCTION__);
{
DBG("%s\n",__FUNCTION__);
cancel_delayed_work(&wakeup_work);
#ifdef CONFIG_BT_AUTOSLEEP
bcm4325_sleep(1);
#endif
DBG("Disable UART_RTS\n");
//To prevent uart to receive bt data when suspended
IOMUX_UART_RTS_GPIO();
gpio_request(UART_RTS, "uart_rts");
gpio_set_value(UART_RTS, GPIO_HIGH);
// enable bt wakeup host
DBG("Request irq for bt wakeup host\n");
if (0 == request_irq(BT_IRQ_WAKE_UP_HOST,
bcm4329_wake_host_irq,
IRQF_TRIGGER_FALLING,
"bt_wake",
NULL))
enable_irq_wake(BT_IRQ_WAKE_UP_HOST);
else
LOG("Failed to request BT_WAKE_UP_HOST irq\n");
#ifdef CONFIG_RFKILL_RESET
extern void rfkill_set_block(struct rfkill *rfkill, bool blocked);
rfkill_set_block(gBtCtrl.bt_rfk, true);
#endif
return 0;
}
static int bcm4329_rfkill_resume(struct platform_device *pdev)
{
DBG("%s\n",__FUNCTION__);
btWakeupHostLock();
resetBtHostSleepTimer();
DBG("%s\n",__FUNCTION__);
// ϵͳ<CFB5>˳<EFBFBD><CBB3><EFBFBD><EFBFBD><EFBFBD>˯<EFBFBD>ߺ<EFBFBD><DFBA><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>RTS<54><53><EFBFBD>Ӷ<EFBFBD><D3B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>BT<42><54><EFBFBD><EFBFBD><EFBFBD>ݹ<EFBFBD><DDB9><EFBFBD>
// <20><><EFBFBD><EFBFBD>Ŀǰ<C4BF><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>resume<6D><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>RTS<54><EFBFBD><E1B5BC>BT<42><54><EFBFBD>ݶ<EFBFBD>ʧ
// <20><><EFBFBD><EFBFBD><EFBFBD>ӳ<EFBFBD>1s<31><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>RTS
// ϵͳ<CFB5>˳<EFBFBD><CBB3><EFBFBD><EFBFBD><EFBFBD>˯<EFBFBD><CBAF>ʱ<EFBFBD>ͷŵ<CDB7>BT_IRQ_WAKE_UP_HOST<53><54><EFBFBD><EFBFBD>˯<EFBFBD><CBAF>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>
// <20><><EFBFBD><EFBFBD><EFBFBD>룬Ŀǰ<C4BF><C7B0><EFBFBD><EFBFBD><EFBFBD>жϻص<CFBB><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>resume<6D><65><EFBFBD><EFBFBD>ִ<EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD>resume
// ʱֱ<CAB1><D6B1>free<65><65>IRQ<52><51><EFBFBD><EFBFBD><E1B5BC><EFBFBD>жϻص<CFBB><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ᱻִ<E1B1BB>У<EFBFBD>
DBG("delay 1s\n");
schedule_delayed_work(&wakeup_work, HZ);
return 0;
}
#else
@@ -126,68 +251,66 @@ static int bcm4329_rfkill_resume(struct platform_device *pdev)
#define bcm4329_rfkill_resume NULL
#endif
static irqreturn_t bcm4329_wake_host_irq(int irq, void *dev)
{
btWakeupHostLock();
resetBtHostSleepTimer();
return IRQ_HANDLED;
}
#endif
#ifdef CONFIG_BT_HCIBCM4325
int bcm4325_sleep(int bSleep)
void bcm4325_sleep(unsigned long bSleep)
{
DBG("*************bt enter sleep***************\n");
if (bSleep)
gpio_set_value(BT_GPIO_WAKE_UP, GPIO_LOW); //low represent bt device may enter sleep
else
gpio_set_value(BT_GPIO_WAKE_UP, GPIO_HIGH); //high represent bt device must be awake
DBG("sleep=%d\n",bSleep);
return 0;
}
DBG("*** bt sleep: %d ***\n", bSleep);
#ifdef CONFIG_BT_AUTOSLEEP
del_timer(&bt_sleep_tl);// cmy: ȷ<><C8B7><EFBFBD>ڻ<EFBFBD><DABB><EFBFBD>BTʱ<54><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򴥷<EFBFBD>bt_sleep_tl<74><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˯<EFBFBD><CBAF>
#endif
IOMUX_BT_GPIO_WAKE_UP();
gpio_set_value(BT_GPIO_WAKE_UP, bSleep?GPIO_LOW:GPIO_HIGH);
#ifdef CONFIG_BT_AUTOSLEEP
if(!bSleep)
mod_timer(&bt_sleep_tl, jiffies + BT_AUTO_SLEEP_TIMEOUT*HZ);//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ó<EFBFBD>ʱֵ<CAB1><D6B5>
#endif
}
static int bcm4329_set_block(void *data, bool blocked)
{
DBG("%s---blocked :%d\n", __FUNCTION__, blocked);
DBG("set blocked :%d\n", blocked);
IOMUX_BT_GPIO_POWER;
IOMUX_BT_GPIO_RESET;
IOMUX_BT_GPIO_POWER;
IOMUX_BT_GPIO_RESET;
if (false == blocked) {
gpio_set_value(BT_GPIO_POWER, GPIO_HIGH); /* bt power on */
gpio_set_value(BT_GPIO_RESET, GPIO_LOW);
mdelay(20);
gpio_set_value(BT_GPIO_RESET, GPIO_HIGH); /* bt reset deactive*/
mdelay(20);
if (false == blocked) {
gpio_set_value(BT_GPIO_POWER, GPIO_HIGH); /* bt power on */
mdelay(20);
gpio_set_value(BT_GPIO_RESET, GPIO_LOW);
mdelay(20);
gpio_set_value(BT_GPIO_RESET, GPIO_HIGH); /* bt reset deactive*/
mdelay(20);
bcm4325_sleep(0); // ensure bt is wakeup
#if BT_WAKE_HOST_SUPPORT
btWakeupHostLock();
#endif
pr_info("bt turn on power\n");
}
else {
#if BT_WAKE_HOST_SUPPORT
btWakeupHostUnlock();
pr_info("bt turn on power\n");
} else {
#if WIFI_BT_POWER_TOGGLE
if (!rk29sdk_wifi_power_state) {
#endif
gpio_set_value(BT_GPIO_POWER, GPIO_LOW); /* bt power off */
mdelay(20);
pr_info("bt shut off power\n");
#if WIFI_BT_POWER_TOGGLE
}else {
pr_info("bt shouldn't shut off power, wifi is using it!\n");
}
#endif
if (!rk29sdk_wifi_power_state) {
gpio_set_value(BT_GPIO_POWER, GPIO_LOW); /* bt power off */
mdelay(20);
pr_info("bt shut off power\n");
}else {
pr_info("bt shouldn't shut off power, wifi is using it!\n");
}
gpio_set_value(BT_GPIO_RESET, GPIO_LOW); /* bt reset active*/
mdelay(20);
}
gpio_set_value(BT_GPIO_RESET, GPIO_LOW); /* bt reset active*/
mdelay(20);
}
rk29sdk_bt_power_state = !blocked;
return 0;
#if WIFI_BT_POWER_TOGGLE
rk29sdk_bt_power_state = !blocked;
#endif
return 0;
}
static const struct rfkill_ops bcm4329_rfk_ops = {
.set_block = bcm4329_set_block,
};
@@ -197,7 +320,7 @@ static int __devinit bcm4329_rfkill_probe(struct platform_device *pdev)
int rc = 0;
bool default_state = true;
DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
DBG("Enter %s\n",__FUNCTION__);
/* default to bluetooth off */
bcm4329_set_block(NULL, default_state); /* blocked -> bt off */
@@ -210,7 +333,7 @@ static int __devinit bcm4329_rfkill_probe(struct platform_device *pdev)
if (!gBtCtrl.bt_rfk)
{
printk("fail to rfkill_allocate************\n");
LOG("fail to rfkill_allocate\n");
return -ENOMEM;
}
@@ -219,20 +342,26 @@ static int __devinit bcm4329_rfkill_probe(struct platform_device *pdev)
rc = rfkill_register(gBtCtrl.bt_rfk);
if (rc)
{
printk("failed to rfkill_register,rc=0x%x\n",rc);
LOG("failed to rfkill_register,rc=0x%x\n",rc);
rfkill_destroy(gBtCtrl.bt_rfk);
}
gpio_request(BT_GPIO_POWER, NULL);
gpio_request(BT_GPIO_RESET, NULL);
#ifdef CONFIG_BT_HCIBCM4325
gpio_request(BT_GPIO_WAKE_UP, NULL);
#ifdef CONFIG_BT_AUTOSLEEP
init_timer(&bt_sleep_tl);
bt_sleep_tl.expires = 0;
bt_sleep_tl.function = bcm4325_sleep;
bt_sleep_tl.data = 1;
add_timer(&bt_sleep_tl);
#endif
#if BT_WAKE_HOST_SUPPORT
init_timer(&(gBtCtrl.tl));
gBtCtrl.tl.expires = jiffies + BT_WAKE_LOCK_TIMEOUT*HZ;
gBtCtrl.tl.function = timer_hostSleep;
gBtCtrl.tl.expires = 0;
gBtCtrl.tl.function = timer_hostSleep;
add_timer(&(gBtCtrl.tl));
gBtCtrl.b_HostWake = false;
@@ -240,22 +369,15 @@ static int __devinit bcm4329_rfkill_probe(struct platform_device *pdev)
rc = gpio_request(BT_GPIO_WAKE_UP_HOST, "bt_wake");
if (rc) {
printk("%s:failed to request RAHO_BT_WAKE_UP_HOST\n",__FUNCTION__);
LOG("Failed to request BT_WAKE_UP_HOST\n");
}
IOMUX_BT_GPIO_WAKE_UP_HOST();
gpio_pull_updown(BT_GPIO_WAKE_UP_HOST,GPIOPullUp);
rc = request_irq(gpio_to_irq(BT_GPIO_WAKE_UP_HOST),bcm4329_wake_host_irq,IRQF_TRIGGER_FALLING,NULL,NULL);
if(rc)
{
printk("%s:failed to request RAHO_BT_WAKE_UP_HOST irq\n",__FUNCTION__);
gpio_free(BT_GPIO_WAKE_UP_HOST);
}
enable_irq_wake(gpio_to_irq(BT_GPIO_WAKE_UP_HOST)); // so RAHO_BT_WAKE_UP_HOST can wake up system
printk(KERN_INFO "bcm4329 module has been initialized,rc=0x%x\n",rc);
#endif
LOG("bcm4329 module has been initialized,rc=0x%x\n",rc);
return rc;
}
@@ -265,14 +387,18 @@ static int __devexit bcm4329_rfkill_remove(struct platform_device *pdev)
if (gBtCtrl.bt_rfk)
rfkill_unregister(gBtCtrl.bt_rfk);
gBtCtrl.bt_rfk = NULL;
#if BT_WAKE_HOST_SUPPORT
#if BT_WAKE_HOST_SUPPORT
del_timer(&(gBtCtrl.tl));//ɾ<><C9BE><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
btWakeupHostUnlock();
wake_lock_destroy(&(gBtCtrl.bt_wakelock));
#endif
#endif
#ifdef CONFIG_BT_AUTOSLEEP
del_timer(&bt_sleep_tl);
#endif
platform_set_drvdata(pdev, NULL);
DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
DBG("Enter %s\n",__FUNCTION__);
return 0;
}
@@ -295,9 +421,9 @@ static struct platform_driver bcm4329_rfkill_driver = {
static int __init bcm4329_mod_init(void)
{
int ret;
DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
DBG("Enter %s\n",__FUNCTION__);
ret = platform_driver_register(&bcm4329_rfkill_driver);
printk("ret=0x%x\n", ret);
LOG("ret=0x%x\n", ret);
return ret;
}
@@ -308,7 +434,7 @@ static void __exit bcm4329_mod_exit(void)
module_init(bcm4329_mod_init);
module_exit(bcm4329_mod_exit);
MODULE_DESCRIPTION("bcm4330 Bluetooth driver");
MODULE_DESCRIPTION("bcm4329 Bluetooth driver");
MODULE_AUTHOR("roger_chen cz@rock-chips.com, cmy@rock-chips.com");
MODULE_LICENSE("GPL");