mt6622 driver update to support 4.2
[firefly-linux-kernel-4.4.55.git] / drivers / mtk_wcn_bt / bt_hwctl_dev.c
1 /* Copyright Statement:
2  *
3  * This software/firmware and related documentation ("MediaTek Software") are
4  * protected under relevant copyright laws. The information contained herein is
5  * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
6  * the prior written permission of MediaTek inc. and/or its licensors, any
7  * reproduction, modification, use or disclosure of MediaTek Software, and
8  * information contained herein, in whole or in part, shall be strictly
9  * prohibited.
10  * 
11  * MediaTek Inc. (C) 2010. All rights reserved.
12  * 
13  * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
14  * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
15  * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
16  * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
17  * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
19  * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
20  * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
21  * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
22  * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
23  * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
24  * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
25  * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
26  * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
27  * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
28  * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
29  * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
30  * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
31  * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
32  *
33  * The following software/firmware and/or related documentation ("MediaTek
34  * Software") have been modified by MediaTek Inc. All revisions are subject to
35  * any receiver's applicable license agreements with MediaTek Inc.
36  */
37
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/init.h>
41 #include <linux/types.h>
42 #include <linux/wait.h>
43 #include <linux/slab.h>
44 #include <linux/fs.h>
45 #include <linux/sched.h>
46 #include <linux/poll.h>
47 #include <linux/device.h>
48 #include <linux/platform_device.h>
49 #include <linux/cdev.h>
50 #include <linux/errno.h>
51 #include <asm/io.h>
52 #include <asm/uaccess.h>
53 #include <net/bluetooth/bluetooth.h>
54 #include <net/bluetooth/hci_core.h>
55 #include <linux/gpio.h>
56 #include <mach/gpio.h>
57
58 #include "bt_hwctl.h"
59
60
61 #define BT_HWCTL_DEBUG_EN     0
62
63 #define BT_HWCTL_ALERT(f, s...) \
64     printk(KERN_ALERT "BTHWCTL " f, ## s)
65
66 #if BT_HWCTL_DEBUG_EN
67 #define BT_HWCTL_DEBUG(f, s...) \
68     printk(KERN_INFO "BTHWCTL " f, ## s)
69 #else
70 #define BT_HWCTL_DEBUG(f, s...) \
71     ((void)0)
72 #endif
73
74 /**************************************************************************
75  *                        D E F I N I T I O N S                           *
76 ***************************************************************************/
77
78 #define BTHWCTL_NAME                 "bthwctl"
79 #define BTHWCTL_DEV_NAME             "/dev/bthwctl"
80 #define BTHWCTL_IOC_MAGIC            0xf6
81 #define BTHWCTL_IOCTL_SET_POWER      _IOWR(BTHWCTL_IOC_MAGIC, 0, uint32_t)
82 #define BTHWCTL_IOCTL_SET_EINT       _IOWR(BTHWCTL_IOC_MAGIC, 1, uint32_t)
83
84 wait_queue_head_t eint_wait;
85 int eint_gen;
86 int eint_mask;
87 int eint_handle_method = 0; // 0: for 4.1; 1: for 4.2 
88
89 struct bt_hwctl {
90     bool powerup;
91     dev_t dev_t;
92     struct class *cls;
93     struct device *dev;
94     struct cdev cdev;
95     struct mutex sem;
96 };
97 static struct bt_hwctl *bh = NULL;
98
99 static struct mt6622_platform_data *mt6622_pdata;
100
101 /*****************************************************************************
102  *  bt_hwctl_open
103 *****************************************************************************/
104 static int bt_hwctl_open(struct inode *inode, struct file *file)
105 {
106     BT_HWCTL_DEBUG("bt_hwctl_open\n");
107     eint_gen = 0;
108     eint_mask = 0;
109     return 0;
110 }
111
112 /*****************************************************************************
113  *  bt_hwctl_ioctl
114 *****************************************************************************/
115 static long bt_hwctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
116 {
117     int ret = 0;
118      
119     BT_HWCTL_DEBUG("bt_hwctl_ioctl\n");
120     
121     if(!bh) {
122         BT_HWCTL_ALERT("bt_hwctl struct not initialized\n");
123         return -EFAULT;
124     }
125     
126     switch(cmd)
127     {
128         case BTHWCTL_IOCTL_SET_POWER:
129         {
130             unsigned long pwr = 0;
131             if (copy_from_user(&pwr, (void*)arg, sizeof(unsigned long)))
132                 return -EFAULT;
133                 
134             BT_HWCTL_DEBUG("BTHWCTL_IOCTL_SET_POWER: %d\n", (int)pwr);
135             
136             mutex_lock(&bh->sem);
137             if (pwr){
138                 ret = mt_bt_power_on();
139             }
140             else{
141                 mt_bt_power_off();
142             }
143             mutex_unlock(&bh->sem);
144             
145             break;
146         }
147         case BTHWCTL_IOCTL_SET_EINT:
148         {
149             unsigned long eint = 0;
150             if (copy_from_user(&eint, (void*)arg, sizeof(unsigned long)))
151                 return -EFAULT;
152                 
153             BT_HWCTL_DEBUG("BTHWCTL_IOCTL_SET_EINT: %d\n", (int)eint);
154             
155             mutex_lock(&bh->sem);
156             if (eint){
157                 /* Enable irq from user space */ 
158                 BT_HWCTL_DEBUG("Set BT EINT enable\n");
159                 mt_bt_enable_irq();
160             }
161             else{
162                 /* Disable irq from user space, maybe time to close driver */
163                 BT_HWCTL_DEBUG("Set BT EINT disable\n");
164                 mt_bt_disable_irq();
165                 eint_mask = 1;
166                 wake_up_interruptible(&eint_wait);
167             }
168             mutex_unlock(&bh->sem);
169             
170             break;
171         }    
172         default:
173             BT_HWCTL_ALERT("BTHWCTL_IOCTL not support\n");
174             return -EPERM;
175     }
176     
177     return ret;
178 }
179
180 /*****************************************************************************
181  *  bt_hwctl_release
182 *****************************************************************************/
183 static int bt_hwctl_release(struct inode *inode, struct file *file)
184 {
185     BT_HWCTL_DEBUG("bt_hwctl_release\n");
186     eint_gen = 0;
187     eint_mask = 0;
188     return 0;
189 }
190
191 /*****************************************************************************
192  *  bt_hwctl_poll
193 *****************************************************************************/
194 static unsigned int bt_hwctl_poll(struct file *file, poll_table *wait)
195 {
196     uint32_t mask = 0;
197    
198     eint_handle_method = 1;
199          
200     BT_HWCTL_DEBUG("bt_hwctl_poll eint_gen %d, eint_mask %d ++\n", eint_gen, eint_mask);
201     //poll_wait(file, &eint_wait, wait);
202     wait_event_interruptible(eint_wait, (eint_gen == 1 || eint_mask == 1));
203     BT_HWCTL_DEBUG("bt_hwctl_poll eint_gen %d, eint_mask %d --\n", eint_gen, eint_mask);
204     
205     if(eint_gen == 1){
206         mask = POLLIN|POLLRDNORM;
207         eint_gen = 0;
208     }
209     else if (eint_mask == 1){
210         mask = POLLERR;
211         eint_mask = 0;
212     }
213     
214     return mask;
215 }
216
217 static void mtk_wcn_bt_work_fun(struct work_struct *work)
218 {
219     struct hci_dev *hdev = NULL;
220
221     /* BlueZ stack, hci_uart driver */
222     hdev = hci_dev_get(0);
223     if(hdev == NULL){
224         /* Avoid the early interrupt before hci0 registered */
225         //printk(KERN_ALERT "hdev is NULL\n ");
226     }else{
227         //printk(KERN_ALERT "Send host wakeup command\n");
228         hci_send_cmd(hdev, 0xFCC1, 0, NULL);
229     }
230     
231     mt_bt_enable_irq();
232 }
233
234 static int mt6622_probe(struct platform_device *pdev)
235 {
236     struct mt6622_platform_data *pdata = pdev->dev.platform_data;
237     
238     printk("mt6622_probe.\n");
239     
240     mt6622_pdata = pdata;
241     if(pdata == NULL) {
242         printk("mt6622_probe failed.\n");
243         return -1;
244     }
245     
246                 if(pdata->power_gpio.io != INVALID_GPIO) {
247                         if (gpio_request(pdata->power_gpio.io, "BT_PWR_EN")){
248                                 printk("mt6622 power_gpio is busy!\n");
249                                 //return -1;
250                         }
251                 }
252                 
253                 if(pdata->reset_gpio.io != INVALID_GPIO) {
254                         if (gpio_request(pdata->reset_gpio.io, "BT_RESET")){
255                                 printk("mt6622 reset_gpio is busy!\n");
256                                 gpio_free(pdata->power_gpio.io);
257                                 //return -1;
258                         }
259                 }
260                 
261                 if(pdata->irq_gpio.io != INVALID_GPIO) {
262                         if (gpio_request(pdata->irq_gpio.io, "BT_EINT")){
263                                 printk("mt6622 irq_gpio is busy!\n");
264                                 gpio_free(pdata->power_gpio.io);
265                                 gpio_free(pdata->reset_gpio.io);
266                                 //return -1;
267                         }
268                 }
269                 
270                 mt_bt_power_init();
271                 
272                 return 0;
273 }
274
275 static int mt6622_remove(struct platform_device *pdev)
276 {
277         struct mt6622_platform_data *pdata = pdev->dev.platform_data;
278         
279         printk("mt6622_remove.\n");
280         
281         if(pdata) {
282           if(pdata->power_gpio.io != INVALID_GPIO)
283                 gpio_free(pdata->power_gpio.io);
284           if(pdata->reset_gpio.io != INVALID_GPIO)
285                 gpio_free(pdata->reset_gpio.io);
286           if(pdata->irq_gpio.io != INVALID_GPIO)
287                 gpio_free(pdata->irq_gpio.io);
288   }
289         
290         return 0;
291 }
292
293 void *mt_bt_get_platform_data(void)
294 {
295         return (void *)mt6622_pdata;
296 }
297
298 /**************************************************************************
299  *                K E R N E L   I N T E R F A C E S                       *
300 ***************************************************************************/
301 static struct file_operations bt_hwctl_fops = {
302     .owner      = THIS_MODULE,
303 //    .ioctl      = bt_hwctl_ioctl,
304     .unlocked_ioctl = bt_hwctl_ioctl,
305     .open       = bt_hwctl_open,
306     .release    = bt_hwctl_release,
307     .poll       = bt_hwctl_poll,
308 };
309
310 static struct platform_driver mt6622_driver = {
311     .probe = mt6622_probe,
312     .remove = mt6622_remove,
313     //.suspend = mt6622_suspend,
314     //.resume = mt6622_resume,
315     .driver = {
316         .name = "mt6622",
317         .owner = THIS_MODULE,
318     },
319 };
320
321 /*****************************************************************************/
322 static int __init bt_hwctl_init(void)
323 {
324     int ret = -1, err = -1;
325     
326     BT_HWCTL_DEBUG("bt_hwctl_init\n");
327     
328     platform_driver_register(&mt6622_driver);
329     
330     if (!(bh = kzalloc(sizeof(struct bt_hwctl), GFP_KERNEL)))
331     {
332         BT_HWCTL_ALERT("bt_hwctl_init allocate dev struct failed\n");
333         err = -ENOMEM;
334         goto ERR_EXIT;
335     }
336     
337     ret = alloc_chrdev_region(&bh->dev_t, 0, 1, BTHWCTL_NAME);
338     if (ret) {
339         BT_HWCTL_ALERT("alloc chrdev region failed\n");
340         goto ERR_EXIT;
341     }
342     
343     BT_HWCTL_DEBUG("alloc %s:%d:%d\n", BTHWCTL_NAME, MAJOR(bh->dev_t), MINOR(bh->dev_t));
344     
345     cdev_init(&bh->cdev, &bt_hwctl_fops);
346     
347     bh->cdev.owner = THIS_MODULE;
348     bh->cdev.ops = &bt_hwctl_fops;
349     
350     err = cdev_add(&bh->cdev, bh->dev_t, 1);
351     if (err) {
352         BT_HWCTL_ALERT("add chrdev failed\n");
353         goto ERR_EXIT;
354     }
355     
356     bh->cls = class_create(THIS_MODULE, BTHWCTL_NAME);
357     if (IS_ERR(bh->cls)) {
358         err = PTR_ERR(bh->cls);
359         BT_HWCTL_ALERT("class_create failed, errno:%d\n", err);
360         goto ERR_EXIT;
361     }
362     
363     bh->dev = device_create(bh->cls, NULL, bh->dev_t, NULL, BTHWCTL_NAME);
364     mutex_init(&bh->sem);
365     
366     init_waitqueue_head(&eint_wait);
367     
368     /*INIT_WORK(&mtk_wcn_bt_event_work, mtk_wcn_bt_work_fun);
369     mtk_wcn_bt_workqueue = create_singlethread_workqueue("mtk_wcn_bt");
370     if (!mtk_wcn_bt_workqueue) {
371         printk("create_singlethread_workqueue failed.\n");
372         err = -ESRCH;
373         goto ERR_EXIT;
374     }*/    
375     
376     /* request gpio used by BT */
377     //mt_bt_gpio_init();
378     
379     BT_HWCTL_DEBUG("bt_hwctl_init ok\n");
380     
381     return 0;
382     
383 ERR_EXIT:
384     if (err == 0)
385         cdev_del(&bh->cdev);
386     if (ret == 0)
387         unregister_chrdev_region(bh->dev_t, 1);
388         
389     if (bh){
390         kfree(bh);
391         bh = NULL;
392     }     
393     return -1;
394 }
395
396 /*****************************************************************************/
397 static void __exit bt_hwctl_exit(void)
398 {
399     BT_HWCTL_DEBUG("bt_hwctl_exit\n");
400     
401     platform_driver_unregister(&mt6622_driver);
402     
403     if (bh){
404         cdev_del(&bh->cdev);
405         
406         unregister_chrdev_region(bh->dev_t, 1);
407         device_destroy(bh->cls, bh->dev_t);
408         
409         class_destroy(bh->cls);
410         mutex_destroy(&bh->sem);
411         
412         kfree(bh);
413         bh = NULL;
414     }
415     
416     /* release gpio used by BT */
417     //mt_bt_gpio_release();
418 }
419
420 EXPORT_SYMBOL(mt_bt_get_platform_data);
421 EXPORT_SYMBOL(eint_wait);
422 EXPORT_SYMBOL(eint_gen);
423 //EXPORT_SYMBOL(mtk_wcn_bt_event_work);
424 //EXPORT_SYMBOL(mtk_wcn_bt_workqueue);
425
426 module_init(bt_hwctl_init);
427 module_exit(bt_hwctl_exit);
428 MODULE_AUTHOR("Tingting Lei <tingting.lei@mediatek.com>");
429 MODULE_DESCRIPTION("Bluetooth hardware control driver");
430 MODULE_LICENSE("GPL");