2 * Copyright (C) 2010 ROCKCHIP, Inc.
3 * Author: roger_chen <cz@rock-chips.com>
5 * This program is the bluetooth device bcm4329's driver,
9 #include <linux/kernel.h>
10 #include <linux/platform_device.h>
11 #include <linux/module.h>
12 #include <linux/device.h>
13 #include <linux/rfkill.h>
14 #include <linux/delay.h>
15 #include <linux/i2c.h>
16 #include <linux/init.h>
17 #include <linux/slab.h>
18 #include <linux/interrupt.h>
19 #include <linux/wakelock.h>
21 #include <asm/uaccess.h>
22 #include <mach/gpio.h>
24 #include <mach/iomux.h>
25 #include <linux/wakelock.h>
26 #include <linux/timer.h>
29 #define DBG(x...) printk(KERN_INFO x)
34 #define BT_WAKE_HOST_SUPPORT 0
38 struct rfkill *bt_rfk;
39 #if BT_WAKE_HOST_SUPPORT
42 struct wake_lock bt_wakelock;
46 #define BT_GPIO_POWER RK29_PIN5_PD6
47 #define IOMUX_BT_GPIO_POWER rk29_mux_api_set(GPIO5D6_SDMMC1PWREN_NAME, GPIO5H_GPIO5D6);
48 #define BT_GPIO_RESET RK29_PIN6_PC4
49 #define BT_GPIO_WAKE_UP RK29_PIN6_PC5
50 #define BT_GPIO_WAKE_UP_HOST //RK2818_PIN_PA7
51 #define IOMUX_BT_GPIO_WAKE_UP_HOST() //rk2818_mux_api_set(GPIOA7_FLASHCS3_SEL_NAME,0);
53 #define BT_WAKE_LOCK_TIMEOUT 10 //s
55 static const char bt_name[] = "bcm4329";
56 extern int rk29sdk_bt_power_state;
57 extern int rk29sdk_wifi_power_state;
59 struct bt_ctrl gBtCtrl;
61 #if BT_WAKE_HOST_SUPPORT
62 void resetBtHostSleepTimer(void)
64 mod_timer(&(gBtCtrl.tl),jiffies + BT_WAKE_LOCK_TIMEOUT*HZ);//ÔÙÖØÐÂÉèÖó¬Ê±Öµ¡£
67 void btWakeupHostLock(void)
69 if(gBtCtrl.b_HostWake == false){
70 DBG("*************************Lock\n");
71 wake_lock(&(gBtCtrl.bt_wakelock));
72 gBtCtrl.b_HostWake = true;
76 void btWakeupHostUnlock(void)
78 if(gBtCtrl.b_HostWake == true){
79 DBG("*************************UnLock\n");
80 wake_unlock(&(gBtCtrl.bt_wakelock)); //ÈÃϵͳ˯Ãß
81 gBtCtrl.b_HostWake = false;
85 static void timer_hostSleep(unsigned long arg)
87 DBG("%s---b_HostWake=%d\n",__FUNCTION__,gBtCtrl.b_HostWake);
93 static int bcm4329_rfkill_suspend(struct platform_device *pdev, pm_message_t state)
95 DBG("%s\n",__FUNCTION__);
99 static int bcm4329_rfkill_resume(struct platform_device *pdev)
101 DBG("%s\n",__FUNCTION__);
103 resetBtHostSleepTimer();
107 #define bcm4329_rfkill_suspend NULL
108 #define bcm4329_rfkill_resume NULL
111 static irqreturn_t bcm4329_wake_host_irq(int irq, void *dev)
114 resetBtHostSleepTimer();
119 #ifdef CONFIG_BT_HCIBCM4325
120 int bcm4325_sleep(int bSleep)
122 // printk("*************bt enter sleep***************\n");
124 gpio_set_value(BT_GPIO_WAKE_UP, GPIO_LOW); //low represent bt device may enter sleep
126 gpio_set_value(BT_GPIO_WAKE_UP, GPIO_HIGH); //high represent bt device must be awake
128 //printk("sleep=%d\n",bSleep);
132 static int bcm4329_set_block(void *data, bool blocked)
134 DBG("%s---blocked :%d\n", __FUNCTION__, blocked);
138 if (false == blocked) {
139 gpio_set_value(BT_GPIO_POWER, GPIO_HIGH); /* bt power on */
140 gpio_set_value(BT_GPIO_RESET, GPIO_HIGH); /* bt reset deactive*/
143 #if BT_WAKE_HOST_SUPPORT
146 pr_info("bt turn on power\n");
149 #if BT_WAKE_HOST_SUPPORT
150 btWakeupHostUnlock();
152 if (!rk29sdk_wifi_power_state) {
153 gpio_set_value(BT_GPIO_POWER, GPIO_LOW); /* bt power off */
155 pr_info("bt shut off power\n");
157 pr_info("bt shouldn't shut off power, wifi is using it!\n");
160 gpio_set_value(BT_GPIO_RESET, GPIO_LOW); /* bt reset active*/
164 rk29sdk_bt_power_state = !blocked;
169 static const struct rfkill_ops bcm4329_rfk_ops = {
170 .set_block = bcm4329_set_block,
173 static int __init bcm4329_rfkill_probe(struct platform_device *pdev)
176 bool default_state = true;
178 DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
180 /* default to bluetooth off */
181 bcm4329_set_block(NULL, default_state); /* blocked -> bt off */
183 gBtCtrl.bt_rfk = rfkill_alloc(bt_name,
185 RFKILL_TYPE_BLUETOOTH,
191 printk("fail to rfkill_allocate************\n");
195 rfkill_set_states(gBtCtrl.bt_rfk, default_state, false);
197 rc = rfkill_register(gBtCtrl.bt_rfk);
200 printk("failed to rfkill_register,rc=0x%x\n",rc);
201 rfkill_destroy(gBtCtrl.bt_rfk);
204 gpio_request(BT_GPIO_POWER, NULL);
205 gpio_request(BT_GPIO_RESET, NULL);
206 gpio_request(BT_GPIO_WAKE_UP, NULL);
208 #if BT_WAKE_HOST_SUPPORT
209 init_timer(&(gBtCtrl.tl));
210 gBtCtrl.tl.expires = jiffies + BT_WAKE_LOCK_TIMEOUT*HZ;
211 gBtCtrl.tl.function = timer_hostSleep;
212 add_timer(&(gBtCtrl.tl));
213 gBtCtrl.b_HostWake = false;
215 wake_lock_init(&(gBtCtrl.bt_wakelock), WAKE_LOCK_SUSPEND, "bt_wake");
217 rc = gpio_request(BT_GPIO_WAKE_UP_HOST, "bt_wake");
219 printk("%s:failed to request RAHO_BT_WAKE_UP_HOST\n",__FUNCTION__);
222 IOMUX_BT_GPIO_WAKE_UP_HOST();
223 gpio_pull_updown(BT_GPIO_WAKE_UP_HOST,GPIOPullUp);
224 rc = request_irq(gpio_to_irq(BT_GPIO_WAKE_UP_HOST),bcm4329_wake_host_irq,IRQF_TRIGGER_FALLING,NULL,NULL);
227 printk("%s:failed to request RAHO_BT_WAKE_UP_HOST irq\n",__FUNCTION__);
228 gpio_free(BT_GPIO_WAKE_UP_HOST);
230 enable_irq_wake(gpio_to_irq(BT_GPIO_WAKE_UP_HOST)); // so RAHO_BT_WAKE_UP_HOST can wake up system
232 printk(KERN_INFO "bcm4329 module has been initialized,rc=0x%x\n",rc);
241 static int __devexit bcm4329_rfkill_remove(struct platform_device *pdev)
244 rfkill_unregister(gBtCtrl.bt_rfk);
245 gBtCtrl.bt_rfk = NULL;
246 #if BT_WAKE_HOST_SUPPORT
247 del_timer(&(gBtCtrl.tl));//ɾµô¶¨Ê±Æ÷
248 btWakeupHostUnlock();
249 wake_lock_destroy(&(gBtCtrl.bt_wakelock));
251 platform_set_drvdata(pdev, NULL);
253 DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
257 static struct platform_driver bcm4329_rfkill_driver = {
258 .probe = bcm4329_rfkill_probe,
259 .remove = __devexit_p(bcm4329_rfkill_remove),
261 .name = "rk29sdk_rfkill",
262 .owner = THIS_MODULE,
264 #if BT_WAKE_HOST_SUPPORT
265 .suspend = bcm4329_rfkill_suspend,
266 .resume = bcm4329_rfkill_resume,
271 * Module initialization
273 static int __init bcm4329_mod_init(void)
276 DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
277 ret = platform_driver_register(&bcm4329_rfkill_driver);
278 printk("ret=0x%x\n", ret);
282 static void __exit bcm4329_mod_exit(void)
284 platform_driver_unregister(&bcm4329_rfkill_driver);
287 module_init(bcm4329_mod_init);
288 module_exit(bcm4329_mod_exit);
289 MODULE_DESCRIPTION("bcm4329 Bluetooth driver");
290 MODULE_AUTHOR("roger_chen cz@rock-chips.com");
291 MODULE_LICENSE("GPL");