usb: dwc3: add functions to set force mode
[firefly-linux-kernel-4.4.55.git] / drivers / misc / tcc_bt_dev.c
1 \r
2 /*\r
3  *  Copyright (C) 2010-2011  RDA Micro <anli@rdamicro.com>\r
4  *  This file belong to RDA micro\r
5  * File:        drivers/char/tcc_bt_dev.c\r
6  */\r
7 \r
8 #include <linux/kernel.h>\r
9 #include <linux/module.h>\r
10 #include <linux/fs.h>\r
11 #include <asm/uaccess.h>\r
12 #include <linux/ioctl.h>\r
13 #include <linux/device.h>\r
14 #include <asm/io.h>\r
15 #include <linux/delay.h>\r
16 #include <linux/gpio.h>\r
17 #include <mach/gpio.h>\r
18 #include <asm/mach-types.h>\r
19 #include <mach/iomux.h>\r
20 #include <linux/interrupt.h>\r
21 #include <asm/irq.h>\r
22 #include <linux/wakelock.h>\r
23 #include <linux/rfkill-rk.h>\r
24 #include <linux/platform_device.h>\r
25 \r
26 #include <net/bluetooth/bluetooth.h>\r
27 #include <net/bluetooth/hci_core.h>\r
28 \r
29 \r
30 #ifndef HOST_WAKE_DELAY\r
31 #define HOST_WAKE_DELAY\r
32 #endif\r
33 \r
34 #define DEV_NAME "tcc_bt_dev"\r
35 \r
36 #define BT_DEV_MAJOR_NUM                    234\r
37 #define BT_DEV_MINOR_NUM                    0\r
38 \r
39 #define IOCTL_BT_DEV_POWER          _IO(BT_DEV_MAJOR_NUM, 100)\r
40 #define IOCTL_BT_SET_EINT        _IO(BT_DEV_MAJOR_NUM, 101)\r
41 \r
42 static wait_queue_head_t        eint_wait;\r
43 static struct work_struct       rda_bt_event_work;\r
44 //static struct workqueue_struct *rda_bt_workqueue;
45 \r
46 static int irq_num  = -1;
47 static int eint_gen;\r
48 static int eint_mask;\r
49 static struct class *bt_dev_class;\r
50 static struct mutex  sem;\r
51 static struct tcc_bt_platform_data *tcc_bt_pdata = NULL;\r
52 static int irq_flag = 0;
53
54
55 static void rda_bt_enable_irq(void)\r
56 {
57     if((irq_num != -1) && (irq_flag == 0))
58     {
59         enable_irq(irq_num);
60         irq_flag = 1;
61     }
62 }
63
64 static void rda_bt_disable_irq(void)\r
65 {
66     if((irq_num != -1) && (irq_flag == 1))
67     {   
68         disable_irq_nosync(irq_num);
69         irq_flag = 0;
70     }       
71 }
72
73 #if 0
74 static void rda_bt_work_fun(struct work_struct *work)\r
75 {\r
76     struct hci_dev *hdev = NULL;\r
77 \r
78     /* BlueZ stack, hci_uart driver */\r
79     hdev = hci_dev_get(0);\r
80     \r
81     if(hdev == NULL)\r
82     {\r
83         /* Avoid the early interrupt before hci0 registered */\r
84         //printk(KERN_ALERT "hdev is NULL\n ");\r
85     }\r
86     else\r
87     {\r
88         printk(KERN_ALERT "Send host wakeup command.\n");\r
89         hci_send_cmd(hdev, 0xC0FC, 0, NULL);\r
90     }\r
91     \r
92     rda_bt_enable_irq();\r
93 }
94 #endif
95
96 static int tcc_bt_dev_open(struct inode *inode, struct file *file)\r
97 {\r
98     printk("[## BT ##] tcc_bt_dev_open.\n");\r
99     eint_gen  = 0;\r
100     eint_mask = 0;\r
101     return 0;\r
102 }\r
103 \r
104 static int tcc_bt_dev_release(struct inode *inode, struct file *file)\r
105 {\r
106     printk("[## BT ##] tcc_bt_dev_release.\n");\r
107     eint_gen  = 0;\r
108     eint_mask = 0;\r
109     return 0;\r
110 }\r
111 \r
112 /*****************************************************************************\r
113  *  tcc_bt_dev_poll\r
114 *****************************************************************************/\r
115 \r
116 static unsigned int tcc_bt_dev_poll(struct file *file, poll_table *wait)\r
117 {\r
118     uint32_t mask = 0;\r
119     \r
120     printk("[## BT ##] tcc_bt_poll eint_gen %d, eint_mask %d ++\n", eint_gen, eint_mask);\r
121 \r
122     wait_event_interruptible(eint_wait, (eint_gen == 1 || eint_mask == 1));\r
123     \r
124     printk("[## BT ##] tcc_bt_poll eint_gen %d, eint_mask %d --\n", eint_gen, eint_mask);\r
125     \r
126     if(eint_gen == 1)\r
127     {\r
128         mask = POLLIN|POLLRDNORM;\r
129         eint_gen = 0;\r
130     }\r
131     else if (eint_mask == 1)\r
132     {\r
133         mask = POLLERR;\r
134         eint_mask = 0;\r
135     }\r
136     \r
137     return mask;\r
138 }\r
139 \r
140 static int tcc_bt_power_control(int on_off)\r
141 {    \r
142     printk("[## BT ##] tcc_bt_power_control input[%d].\n", on_off);\r
143         \r
144     if(on_off)\r
145     {       \r
146          gpio_direction_output(tcc_bt_pdata->power_gpio.io, tcc_bt_pdata->power_gpio.enable);\r
147          msleep(500);
148          rda_bt_enable_irq();
149     }\r
150     else\r
151     {\r
152         gpio_direction_output(tcc_bt_pdata->power_gpio.io, !tcc_bt_pdata->power_gpio.enable);\r
153         rda_bt_disable_irq();
154         msleep(500);\r
155     }\r
156 \r
157     return 0;\r
158 }\r
159 \r
160 \r
161 static long  tcc_bt_dev_ioctl(struct file *file, unsigned int cmd,unsigned long arg)\r
162 {\r
163     void __user *argp = (void __user *)arg;\r
164     int  ret   = -1;\r
165     int  rate  = 0;\r
166 \r
167     switch(cmd)\r
168     {\r
169         case IOCTL_BT_DEV_POWER:\r
170         {\r
171             printk("[## BT ##] IOCTL_BT_DEV_POWER cmd[%d] parm1[%d].\n", cmd, rate);\r
172             if (copy_from_user(&rate, argp, sizeof(rate)))\r
173                 return -EFAULT;\r
174 \r
175             mutex_lock(&sem);  \r
176             ret = tcc_bt_power_control(rate);\r
177             mutex_unlock(&sem);                 \r
178             break;\r
179         }               \r
180                 \r
181         case IOCTL_BT_SET_EINT:\r
182         {\r
183             if (copy_from_user(&rate, argp, sizeof(rate)))\r
184                 return -EFAULT;\r
185             printk("[## BT ##] IOCTL_BT_SET_EINT cmd[%d].\n", cmd);\r
186             mutex_lock(&sem); \r
187 \r
188             if(rate)\r
189             {\r
190                 rda_bt_enable_irq();\r
191             }\r
192             else\r
193             {\r
194                 rda_bt_disable_irq();\r
195                 eint_mask = 1;\r
196                 wake_up_interruptible(&eint_wait);\r
197             }             \r
198             mutex_unlock(&sem); \r
199             ret = 0;\r
200             break;\r
201         }\r
202         \r
203         default :\r
204         {\r
205                  printk("[## BT ##] tcc_bt_dev_ioctl cmd[%d].\n", cmd);\r
206                  break;\r
207             }\r
208     }\r
209 \r
210     return ret;\r
211 }\r
212 \r
213 \r
214 struct file_operations tcc_bt_dev_ops = \r
215 {\r
216     .owner           = THIS_MODULE,\r
217     .unlocked_ioctl  = tcc_bt_dev_ioctl,\r
218     .open            = tcc_bt_dev_open,\r
219     .release         = tcc_bt_dev_release,\r
220     .poll            = tcc_bt_dev_poll,\r
221 };\r
222 \r
223 #ifdef HOST_WAKE_DELAY\r
224 struct wake_lock rda_bt_wakelock;\r
225 #endif\r
226 \r
227 static irqreturn_t rda_bt_host_wake_irq(int irq, void *dev)\r
228 {\r
229     printk("rda_bt_host_wake_irq.\n");\r
230     rda_bt_disable_irq();       
231
232 #ifdef HOST_WAKE_DELAY\r
233     wake_lock_timeout(&rda_bt_wakelock, 3 * HZ); \r
234 #endif
235
236 #if 0 //CONFIG_BT_HCIUART
237     if(rda_bt_workqueue)
238         queue_work(rda_bt_workqueue, &rda_bt_event_work);\r
239 #else\r
240     /* Maybe handle the interrupt in user space? */\r
241     eint_gen = 1;\r
242     wake_up_interruptible(&eint_wait);\r
243     /* Send host wakeup command in user space, enable irq then */\r
244 #endif
245     
246     return IRQ_HANDLED;
247 }
248
249 static int tcc_bt_probe(struct platform_device *pdev)\r
250 {\r
251     int ret;\r
252 \r
253     struct tcc_bt_platform_data *pdata = pdev->dev.platform_data;\r
254     \r
255     printk("tcc_bt_probe.\n");\r
256     if(pdata == NULL) {\r
257         printk("tcc_bt_probe failed.\n");\r
258         return -1;\r
259     }\r
260     tcc_bt_pdata = pdata;\r
261     \r
262     if(pdata->power_gpio.io != INVALID_GPIO) {\r
263         if (gpio_request(pdata->power_gpio.io, "ldoonpin")){\r
264             printk("tcc bt ldoonpin is busy!\n");\r
265             return -1;\r
266         }\r
267     }\r
268     gpio_direction_output(pdata->power_gpio.io, !pdata->power_gpio.enable);//GPIO_LOW\r
269     \r
270 #ifdef HOST_WAKE_DELAY\r
271     wake_lock_init(&rda_bt_wakelock, WAKE_LOCK_SUSPEND, "rda_bt_wake");\r
272 #endif\r
273 \r
274     if(pdata->wake_host_gpio.io != INVALID_GPIO) {\r
275         if (gpio_request(pdata->wake_host_gpio.io, "tcc_bt_wake")){\r
276             printk("tcc bt wakeis busy!\n");\r
277             gpio_free(pdata->wake_host_gpio.io);\r
278             return -1;\r
279         }\r
280     }   \r
281 \r
282     gpio_direction_input(pdata->wake_host_gpio.io);\r
283     irq_num = gpio_to_irq(pdata->wake_host_gpio.io);\r
284     ret = request_irq(irq_num, rda_bt_host_wake_irq, pdata->wake_host_gpio.enable, "tcc_bt_host_wake",NULL);       \r
285     if(ret < 0)\r
286     {\r
287         printk("bt_host_wake irq request fail.\n");\r
288           irq_num = -1;\r
289         goto error;\r
290     }\r
291
292     enable_irq_wake(irq_num);
293     irq_flag = 1;
294     rda_bt_disable_irq();
295
296     mutex_init(&sem);   \r
297     printk("[## BT ##] init_module\n");\r
298         \r
299     ret = register_chrdev(BT_DEV_MAJOR_NUM, DEV_NAME, &tcc_bt_dev_ops);\r
300     if(ret < 0)\r
301     {\r
302         printk("[## BT ##] [%d]fail to register the character device.\n", ret);\r
303         goto error;\r
304     }\r
305     \r
306     bt_dev_class = class_create(THIS_MODULE, DEV_NAME);\r
307     if (IS_ERR(bt_dev_class)) \r
308     {\r
309         printk("BT RDA class_create failed\n");\r
310         goto error;\r
311     }\r
312         \r
313     device_create(bt_dev_class, NULL, MKDEV(BT_DEV_MAJOR_NUM, BT_DEV_MINOR_NUM), NULL, DEV_NAME);\r
314
315     init_waitqueue_head(&eint_wait);\r
316    
317     /*
318     INIT_WORK(&rda_bt_event_work, rda_bt_work_fun);\r
319     rda_bt_workqueue = create_singlethread_workqueue("rda_bt");
320     if (!rda_bt_workqueue)
321     {
322         printk("create_singlethread_workqueue failed.\n");\r
323         ret = -ESRCH;\r
324         goto error;\r
325     } 
326     */
327  
328     return 0;\r
329     \r
330 error:\r
331     gpio_free(pdata->power_gpio.io); \r
332     gpio_free(pdata->wake_host_gpio.io);\r
333     return ret;    \r
334 }\r
335 \r
336 static int tcc_bt_remove(struct platform_device *pdev)\r
337 {\r
338     printk("[## BT ##] cleanup_module.\n");
339     free_irq(irq_num, NULL);
340     unregister_chrdev(BT_DEV_MAJOR_NUM, DEV_NAME);\r
341     if(tcc_bt_pdata)\r
342         tcc_bt_pdata = NULL;
343
344     cancel_work_sync(&rda_bt_event_work);\r
345     //destroy_workqueue(rda_bt_workqueue);    \r
346     \r
347 #ifdef HOST_WAKE_DELAY    \r
348     wake_lock_destroy(&rda_bt_wakelock);\r
349 #endif    
350 \r
351     return 0;\r
352 }\r
353 \r
354 static struct platform_driver tcc_bt_driver = {\r
355         .probe = tcc_bt_probe,\r
356         .remove = tcc_bt_remove,\r
357         .driver = {\r
358                 .name = "tcc_bt_dev",\r
359                 .owner = THIS_MODULE,\r
360         },\r
361 };\r
362 \r
363 static int __init tcc_bt_init_module(void)\r
364 {\r
365     printk("Enter %s\n", __func__);\r
366     return platform_driver_register(&tcc_bt_driver);\r
367 }\r
368 \r
369 static void __exit tcc_bt_cleanup_module(void)\r
370 {\r
371     printk("Enter %s\n", __func__);\r
372     platform_driver_unregister(&tcc_bt_driver);\r
373 }\r
374 \r
375 module_init(tcc_bt_init_module);\r
376 module_exit(tcc_bt_cleanup_module);\r
377 \r
378 \r
379 MODULE_AUTHOR("Telechips Inc. linux@telechips.com");\r
380 MODULE_DESCRIPTION("TCC_BT_DEV");\r
381 MODULE_LICENSE("GPL");\r
382 \r
383 \r