#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)
-struct bt_ctrl
-{
- struct rfkill *bt_rfk;
-#if BT_WAKE_HOST_SUPPORT
- struct timer_list tl;
- bool b_HostWake;
- struct wake_lock bt_wakelock;
+#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 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);
+#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)
+
-#ifdef CONFIG_BT_HCIBCM4325
+// BT wakeup pin
#define BT_GPIO_WAKE_UP RK30_PIN3_PC6
-#endif
+#define IOMUX_BT_GPIO_WAKE_UP() rk29_mux_api_set(GPIO3C6_SDMMC1DETECTN_NAME, GPIO3C_GPIO3C6);
-#if BT_WAKE_HOST_SUPPORT
+// 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 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)
-#define BT_WAKE_LOCK_TIMEOUT 10 //s
+//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
+{
+ struct rfkill *bt_rfk;
+#if BT_WAKE_HOST_SUPPORT
+ struct timer_list tl;
+ bool b_HostWake;
+ struct wake_lock bt_wakelock;
#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)
#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)
{
void btWakeupHostLock(void)
{
if(gBtCtrl.b_HostWake == false){
- DBG("*************************Lock\n");
+ DBG("** Lock **\n");
wake_lock(&(gBtCtrl.bt_wakelock));
gBtCtrl.b_HostWake = true;
}
void btWakeupHostUnlock(void)
{
if(gBtCtrl.b_HostWake == true){
- DBG("*************************UnLock\n");
+ DBG("** UnLock **\n");
wake_unlock(&(gBtCtrl.bt_wakelock)); //ÈÃϵͳ˯Ãß
gBtCtrl.b_HostWake = false;
}
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__);
+
+ // ϵͳÍ˳ö¶þ¼¶Ë¯ÃߺóÐèÒªÀµÍRTS£¬´Ó¶ø²ÅÔÊÐíBT·¢Êý¾Ý¹ýÀ´
+ // µ«ÊÇÄ¿Ç°·¢ÏÖÔÚresumeº¯ÊýÖÐÖ±½ÓÀµÍRTS»áµ¼ÖÂBTÊý¾Ý¶ªÊ§
+ // ËùÒÔÑÓ³Ù1sºóÔÙÀµÍRTS
+ // ϵͳÍ˳ö¶þ¼¶Ë¯ÃßʱÊͷŵôBT_IRQ_WAKE_UP_HOST£¬ÔÚ˯ÃßʱºòÔÙ
+ // ´ÎÉêÇ룬Ŀǰ·¢ÏÖÖжϻص÷º¯Êý±Èresume¸üÍíÖ´ÐУ¬Èç¹ûresume
+ // ʱֱ½ÓfreeµôIRQ£¬»áµ¼ÖÂÖжϻص÷º¯Êý²»»á±»Ö´ÐУ¬
+ DBG("delay 1s\n");
+ schedule_delayed_work(&wakeup_work, HZ);
+
return 0;
}
#else
#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: È·±£ÔÚ»½ÐÑBTʱ£¬²»»áÒò´¥·¢bt_sleep_tl¶øÂíÉÏ˯Ãß
+#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);//ÔÙÖØÐÂÉèÖó¬Ê±Öµ¡£
#endif
-
+}
+
static int bcm4329_set_block(void *data, bool blocked)
{
- DBG("%s---blocked :%d\n", __FUNCTION__, blocked);
-
- 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);
+ DBG("set blocked :%d\n", blocked);
+
+ IOMUX_BT_GPIO_POWER;
+ IOMUX_BT_GPIO_RESET;
+
+ 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
- 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);
- }
-
- rk29sdk_bt_power_state = !blocked;
- return 0;
-}
+ 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
+
+ gpio_set_value(BT_GPIO_RESET, GPIO_LOW); /* bt reset active*/
+ mdelay(20);
+ }
+#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,
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 */
if (!gBtCtrl.bt_rfk)
{
- printk("fail to rfkill_allocate************\n");
+ LOG("fail to rfkill_allocate\n");
return -ENOMEM;
}
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;
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;
}
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));//ɾµô¶¨Ê±Æ÷
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;
}
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;
}
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");