BT: add bluetooth bcm4329 driver
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rk29 / board-rk29sdk-rfkill.c
1 /*
2  * Copyright (C) 2010 ROCKCHIP, Inc.
3  * Author: roger_chen <cz@rock-chips.com>
4  *
5  * This program is the bluetooth device bcm4329's driver,
6  *
7  */
8
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>
20 #include <linux/fs.h>
21 #include <asm/uaccess.h>
22 #include <mach/gpio.h>
23 #include <asm/irq.h>
24 #include <mach/iomux.h>
25 #include <linux/wakelock.h>
26 #include <linux/timer.h>
27
28 #if 0
29 #define DBG(x...)   printk(KERN_INFO x)
30 #else
31 #define DBG(x...)
32 #endif
33
34 #define BT_WAKE_HOST_SUPPORT 0
35
36 struct bt_ctrl
37 {
38     struct rfkill *bt_rfk;
39 #if BT_WAKE_HOST_SUPPORT
40     struct timer_list tl;
41     bool b_HostWake;
42     struct wake_lock bt_wakelock;
43 #endif
44 };
45
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);
52
53 #define BT_WAKE_LOCK_TIMEOUT    10 //s
54
55 static const char bt_name[] = "bcm4329";
56 extern int rk29sdk_bt_power_state;
57 extern int rk29sdk_wifi_power_state;
58
59 struct bt_ctrl gBtCtrl;
60     
61 #if BT_WAKE_HOST_SUPPORT
62 void resetBtHostSleepTimer(void)
63 {
64     mod_timer(&(gBtCtrl.tl),jiffies + BT_WAKE_LOCK_TIMEOUT*HZ);//ÔÙÖØÐÂÉèÖó¬Ê±Öµ¡£    
65 }
66
67 void btWakeupHostLock(void)
68 {
69     if(gBtCtrl.b_HostWake == false){
70         DBG("*************************Lock\n");
71         wake_lock(&(gBtCtrl.bt_wakelock));
72         gBtCtrl.b_HostWake = true;
73     }
74 }
75
76 void btWakeupHostUnlock(void)
77 {
78     if(gBtCtrl.b_HostWake == true){        
79         DBG("*************************UnLock\n");
80         wake_unlock(&(gBtCtrl.bt_wakelock));  //ÈÃϵͳ˯Ãß    
81         gBtCtrl.b_HostWake = false;
82     }    
83 }
84
85 static void timer_hostSleep(unsigned long arg)
86 {     
87         DBG("%s---b_HostWake=%d\n",__FUNCTION__,gBtCtrl.b_HostWake);
88     btWakeupHostUnlock();
89 }
90
91
92 #ifdef CONFIG_PM
93 static int bcm4329_rfkill_suspend(struct platform_device *pdev, pm_message_t state)
94 {   
95     DBG("%s\n",__FUNCTION__);   
96     return 0;
97 }
98
99 static int bcm4329_rfkill_resume(struct platform_device *pdev)
100 {  
101     DBG("%s\n",__FUNCTION__);     
102     btWakeupHostLock();
103     resetBtHostSleepTimer();
104     return 0;
105 }
106 #else
107 #define bcm4329_rfkill_suspend NULL
108 #define bcm4329_rfkill_resume  NULL
109 #endif
110
111 static irqreturn_t bcm4329_wake_host_irq(int irq, void *dev)
112 {
113     btWakeupHostLock();
114     resetBtHostSleepTimer();
115         return IRQ_HANDLED;
116 }
117 #endif
118
119 #ifdef CONFIG_BT_HCIBCM4325
120 int bcm4325_sleep(int bSleep)
121 {
122 //      printk("*************bt enter sleep***************\n");
123     if (bSleep)
124     gpio_set_value(BT_GPIO_WAKE_UP, GPIO_LOW);   //low represent bt device may enter sleep  
125     else
126     gpio_set_value(BT_GPIO_WAKE_UP, GPIO_HIGH);  //high represent bt device must be awake 
127
128         //printk("sleep=%d\n",bSleep);
129 }
130 #endif
131   
132 static int bcm4329_set_block(void *data, bool blocked)
133 {
134         DBG("%s---blocked :%d\n", __FUNCTION__, blocked);
135
136         IOMUX_BT_GPIO_POWER;
137
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*/
141                 mdelay(20);
142         
143 #if BT_WAKE_HOST_SUPPORT     
144             btWakeupHostLock();
145 #endif         
146                 pr_info("bt turn on power\n");
147         }
148         else {
149 #if BT_WAKE_HOST_SUPPORT     
150             btWakeupHostUnlock();
151 #endif
152                 if (!rk29sdk_wifi_power_state) {
153                         gpio_set_value(BT_GPIO_POWER, GPIO_LOW);  /* bt power off */
154                 mdelay(20);     
155                 pr_info("bt shut off power\n");
156                 }else {
157                         pr_info("bt shouldn't shut off power, wifi is using it!\n");
158                 }
159
160                 gpio_set_value(BT_GPIO_RESET, GPIO_LOW);  /* bt reset active*/
161                 mdelay(20);
162         }
163
164         rk29sdk_bt_power_state = !blocked;
165         return 0;
166 }
167
168
169 static const struct rfkill_ops bcm4329_rfk_ops = {
170         .set_block = bcm4329_set_block,
171 };
172
173 static int __init bcm4329_rfkill_probe(struct platform_device *pdev)
174 {
175         int rc = 0;
176         bool default_state = true;
177         
178         DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
179         
180         /* default to bluetooth off */
181         bcm4329_set_block(NULL, default_state); /* blocked -> bt off */
182          
183         gBtCtrl.bt_rfk = rfkill_alloc(bt_name, 
184                 NULL, 
185                 RFKILL_TYPE_BLUETOOTH, 
186                 &bcm4329_rfk_ops, 
187                 NULL);
188
189         if (!gBtCtrl.bt_rfk)
190         {
191                 printk("fail to rfkill_allocate************\n");
192                 return -ENOMEM;
193         }
194         
195         rfkill_set_states(gBtCtrl.bt_rfk, default_state, false);
196
197         rc = rfkill_register(gBtCtrl.bt_rfk);
198         if (rc)
199         {
200                 printk("failed to rfkill_register,rc=0x%x\n",rc);
201                 rfkill_destroy(gBtCtrl.bt_rfk);
202         }
203         
204         gpio_request(BT_GPIO_POWER, NULL);
205         gpio_request(BT_GPIO_RESET, NULL);
206         gpio_request(BT_GPIO_WAKE_UP, NULL);
207
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;
214     
215         wake_lock_init(&(gBtCtrl.bt_wakelock), WAKE_LOCK_SUSPEND, "bt_wake");
216         
217         rc = gpio_request(BT_GPIO_WAKE_UP_HOST, "bt_wake");
218         if (rc) {
219                 printk("%s:failed to request RAHO_BT_WAKE_UP_HOST\n",__FUNCTION__);
220         }
221         
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);
225         if(rc)
226         {
227                 printk("%s:failed to request RAHO_BT_WAKE_UP_HOST irq\n",__FUNCTION__);
228                 gpio_free(BT_GPIO_WAKE_UP_HOST);
229         }
230         enable_irq_wake(gpio_to_irq(BT_GPIO_WAKE_UP_HOST)); // so RAHO_BT_WAKE_UP_HOST can wake up system
231
232         printk(KERN_INFO "bcm4329 module has been initialized,rc=0x%x\n",rc);
233  #endif
234  
235         return rc;
236
237         
238 }
239
240
241 static int __devexit bcm4329_rfkill_remove(struct platform_device *pdev)
242 {
243         if (gBtCtrl.bt_rfk)
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));
250 #endif    
251         platform_set_drvdata(pdev, NULL);
252
253         DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
254         return 0;
255 }
256
257 static struct platform_driver bcm4329_rfkill_driver = {
258         .probe = bcm4329_rfkill_probe,
259         .remove = __devexit_p(bcm4329_rfkill_remove),
260         .driver = {
261                 .name = "rk29sdk_rfkill", 
262                 .owner = THIS_MODULE,
263         },      
264 #if BT_WAKE_HOST_SUPPORT
265     .suspend = bcm4329_rfkill_suspend,
266     .resume = bcm4329_rfkill_resume,
267 #endif
268 };
269
270 /*
271  * Module initialization
272  */
273 static int __init bcm4329_mod_init(void)
274 {
275         int ret;
276         DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
277         ret = platform_driver_register(&bcm4329_rfkill_driver);
278         printk("ret=0x%x\n", ret);
279         return ret;
280 }
281
282 static void __exit bcm4329_mod_exit(void)
283 {
284         platform_driver_unregister(&bcm4329_rfkill_driver);
285 }
286
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");
292