wifi: support mt5931 wifi and mt6622 bt
[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 struct work_struct mtk_wcn_bt_event_work;
88 struct workqueue_struct *mtk_wcn_bt_workqueue;
89
90 struct bt_hwctl {
91     bool powerup;
92     dev_t dev_t;
93     struct class *cls;
94     struct device *dev;
95     struct cdev cdev;
96     struct mutex sem;
97 };
98 static struct bt_hwctl *bh = NULL;
99
100 static struct mt6622_platform_data *mt6622_pdata;
101
102 /*****************************************************************************
103  *  bt_hwctl_open
104 *****************************************************************************/
105 static int bt_hwctl_open(struct inode *inode, struct file *file)
106 {
107     BT_HWCTL_DEBUG("bt_hwctl_open\n");
108     eint_gen = 0;
109     eint_mask = 0;
110     return 0;
111 }
112
113 /*****************************************************************************
114  *  bt_hwctl_ioctl
115 *****************************************************************************/
116 static long bt_hwctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
117 {
118     int ret = 0;
119      
120     BT_HWCTL_DEBUG("bt_hwctl_ioctl\n");
121     
122     if(!bh) {
123         BT_HWCTL_ALERT("bt_hwctl struct not initialized\n");
124         return -EFAULT;
125     }
126     
127     switch(cmd)
128     {
129         case BTHWCTL_IOCTL_SET_POWER:
130         {
131             unsigned long pwr = 0;
132             if (copy_from_user(&pwr, (void*)arg, sizeof(unsigned long)))
133                 return -EFAULT;
134                 
135             BT_HWCTL_DEBUG("BTHWCTL_IOCTL_SET_POWER: %d\n", (int)pwr);
136             
137             mutex_lock(&bh->sem);
138             if (pwr){
139                 ret = mt_bt_power_on();
140             }
141             else{
142                 mt_bt_power_off();
143             }
144             mutex_unlock(&bh->sem);
145             
146             break;
147         }
148         case BTHWCTL_IOCTL_SET_EINT:
149         {
150             unsigned long eint = 0;
151             if (copy_from_user(&eint, (void*)arg, sizeof(unsigned long)))
152                 return -EFAULT;
153                 
154             BT_HWCTL_DEBUG("BTHWCTL_IOCTL_SET_EINT: %d\n", (int)eint);
155             
156             mutex_lock(&bh->sem);
157             if (eint){
158                 /* Enable irq from user space */ 
159                 BT_HWCTL_DEBUG("Set BT EINT enable\n");
160                 mt_bt_enable_irq();
161             }
162             else{
163                 /* Disable irq from user space, maybe time to close driver */
164                 BT_HWCTL_DEBUG("Set BT EINT disable\n");
165                 mt_bt_disable_irq();
166                 eint_mask = 1;
167                 wake_up_interruptible(&eint_wait);
168             }
169             mutex_unlock(&bh->sem);
170             
171             break;
172         }    
173         default:
174             BT_HWCTL_ALERT("BTHWCTL_IOCTL not support\n");
175             return -EPERM;
176     }
177     
178     return ret;
179 }
180
181 /*****************************************************************************
182  *  bt_hwctl_release
183 *****************************************************************************/
184 static int bt_hwctl_release(struct inode *inode, struct file *file)
185 {
186     BT_HWCTL_DEBUG("bt_hwctl_release\n");
187     eint_gen = 0;
188     eint_mask = 0;
189     return 0;
190 }
191
192 /*****************************************************************************
193  *  bt_hwctl_poll
194 *****************************************************************************/
195 static unsigned int bt_hwctl_poll(struct file *file, poll_table *wait)
196 {
197     uint32_t mask = 0;
198     
199     BT_HWCTL_DEBUG("bt_hwctl_poll eint_gen %d, eint_mask %d ++\n", eint_gen, eint_mask);
200     //poll_wait(file, &eint_wait, wait);
201     wait_event_interruptible(eint_wait, (eint_gen == 1 || eint_mask == 1));
202     BT_HWCTL_DEBUG("bt_hwctl_poll eint_gen %d, eint_mask %d --\n", eint_gen, eint_mask);
203     
204     if(eint_gen == 1){
205         mask = POLLIN|POLLRDNORM;
206         eint_gen = 0;
207     }
208     else if (eint_mask == 1){
209         mask = POLLERR;
210         eint_mask = 0;
211     }
212     
213     return mask;
214 }
215
216 static void mtk_wcn_bt_work_fun(struct work_struct *work)
217 {
218     struct hci_dev *hdev = NULL;
219
220     /* BlueZ stack, hci_uart driver */
221     hdev = hci_dev_get(0);
222     if(hdev == NULL){
223         /* Avoid the early interrupt before hci0 registered */
224         //printk(KERN_ALERT "hdev is NULL\n ");
225     }else{
226         //printk(KERN_ALERT "Send host wakeup command\n");
227         hci_send_cmd(hdev, 0xFCC1, 0, NULL);
228     }
229     
230     mt_bt_enable_irq();
231 }
232
233 static int mt6622_probe(struct platform_device *pdev)
234 {
235     struct mt6622_platform_data *pdata = pdev->dev.platform_data;
236     
237     printk("mt6622_probe.\n");
238     
239     mt6622_pdata = pdata;
240     if(pdata == NULL) {
241         printk("mt6622_probe failed.\n");
242         return -1;
243     }
244     
245                 if (gpio_request(pdata->power_gpio.io, "BT_PWR_EN")){
246                         printk("mt6622 power_gpio is busy!\n");
247                         return -1;
248                 }
249                 
250                 if (gpio_request(pdata->reset_gpio.io, "BT_RESET")){
251                         printk("mt6622 reset_gpio is busy!\n");
252                         gpio_free(pdata->power_gpio.io);
253                         return -1;
254                 }
255                 
256                 if (gpio_request(pdata->irq_gpio.io, "BT_EINT")){
257                         printk("mt6622 irq_gpio is busy!\n");
258                         gpio_free(pdata->power_gpio.io);
259                         gpio_free(pdata->reset_gpio.io);
260                         return -1;
261                 }
262                 
263                 return 0;
264 }
265
266 static int mt6622_remove(struct platform_device *pdev)
267 {
268         struct mt6622_platform_data *pdata = pdev->dev.platform_data;
269         
270         printk("mt6622_remove.\n");
271         
272         if(pdata) {
273           gpio_free(pdata->power_gpio.io);
274           gpio_free(pdata->reset_gpio.io);
275           gpio_free(pdata->irq_gpio.io);
276   }
277         
278         return 0;
279 }
280
281 void *mt_bt_get_platform_data(void)
282 {
283         return (void *)mt6622_pdata;
284 }
285
286 /**************************************************************************
287  *                K E R N E L   I N T E R F A C E S                       *
288 ***************************************************************************/
289 static struct file_operations bt_hwctl_fops = {
290     .owner      = THIS_MODULE,
291 //    .ioctl      = bt_hwctl_ioctl,
292     .unlocked_ioctl = bt_hwctl_ioctl,
293     .open       = bt_hwctl_open,
294     .release    = bt_hwctl_release,
295     .poll       = bt_hwctl_poll,
296 };
297
298 static struct platform_driver mt6622_driver = {
299     .probe = mt6622_probe,
300     .remove = mt6622_remove,
301     .driver = {
302         .name = "mt6622",
303         .owner = THIS_MODULE,
304     },
305 };
306
307 /*****************************************************************************/
308 static int __init bt_hwctl_init(void)
309 {
310     int ret = -1, err = -1;
311     
312     BT_HWCTL_DEBUG("bt_hwctl_init\n");
313     
314     platform_driver_register(&mt6622_driver);
315     
316     if (!(bh = kzalloc(sizeof(struct bt_hwctl), GFP_KERNEL)))
317     {
318         BT_HWCTL_ALERT("bt_hwctl_init allocate dev struct failed\n");
319         err = -ENOMEM;
320         goto ERR_EXIT;
321     }
322     
323     ret = alloc_chrdev_region(&bh->dev_t, 0, 1, BTHWCTL_NAME);
324     if (ret) {
325         BT_HWCTL_ALERT("alloc chrdev region failed\n");
326         goto ERR_EXIT;
327     }
328     
329     BT_HWCTL_DEBUG("alloc %s:%d:%d\n", BTHWCTL_NAME, MAJOR(bh->dev_t), MINOR(bh->dev_t));
330     
331     cdev_init(&bh->cdev, &bt_hwctl_fops);
332     
333     bh->cdev.owner = THIS_MODULE;
334     bh->cdev.ops = &bt_hwctl_fops;
335     
336     err = cdev_add(&bh->cdev, bh->dev_t, 1);
337     if (err) {
338         BT_HWCTL_ALERT("add chrdev failed\n");
339         goto ERR_EXIT;
340     }
341     
342     bh->cls = class_create(THIS_MODULE, BTHWCTL_NAME);
343     if (IS_ERR(bh->cls)) {
344         err = PTR_ERR(bh->cls);
345         BT_HWCTL_ALERT("class_create failed, errno:%d\n", err);
346         goto ERR_EXIT;
347     }
348     
349     bh->dev = device_create(bh->cls, NULL, bh->dev_t, NULL, BTHWCTL_NAME);
350     mutex_init(&bh->sem);
351     
352     init_waitqueue_head(&eint_wait);
353     
354     INIT_WORK(&mtk_wcn_bt_event_work, mtk_wcn_bt_work_fun);
355     mtk_wcn_bt_workqueue = create_singlethread_workqueue("mtk_wcn_bt");
356     if (!mtk_wcn_bt_workqueue) {
357         printk("create_singlethread_workqueue failed.\n");
358         err = -ESRCH;
359         goto ERR_EXIT;
360     }    
361     
362     /* request gpio used by BT */
363     //mt_bt_gpio_init();
364     
365     BT_HWCTL_DEBUG("bt_hwctl_init ok\n");
366     
367     return 0;
368     
369 ERR_EXIT:
370     if (err == 0)
371         cdev_del(&bh->cdev);
372     if (ret == 0)
373         unregister_chrdev_region(bh->dev_t, 1);
374         
375     if (bh){
376         kfree(bh);
377         bh = NULL;
378     }     
379     return -1;
380 }
381
382 /*****************************************************************************/
383 static void __exit bt_hwctl_exit(void)
384 {
385     BT_HWCTL_DEBUG("bt_hwctl_exit\n");
386     
387     platform_driver_register(&mt6622_driver);
388     
389     if (bh){
390         cdev_del(&bh->cdev);
391         
392         unregister_chrdev_region(bh->dev_t, 1);
393         device_destroy(bh->cls, bh->dev_t);
394         
395         class_destroy(bh->cls);
396         mutex_destroy(&bh->sem);
397         
398         kfree(bh);
399         bh = NULL;
400     }
401     
402     cancel_work_sync(&mtk_wcn_bt_event_work);
403     destroy_workqueue(mtk_wcn_bt_workqueue);    
404     
405     /* release gpio used by BT */
406     //mt_bt_gpio_release();
407 }
408
409 EXPORT_SYMBOL(mt_bt_get_platform_data);
410 EXPORT_SYMBOL(eint_wait);
411 EXPORT_SYMBOL(eint_gen);
412 EXPORT_SYMBOL(mtk_wcn_bt_event_work);
413 EXPORT_SYMBOL(mtk_wcn_bt_workqueue);
414
415 module_init(bt_hwctl_init);
416 module_exit(bt_hwctl_exit);
417 MODULE_AUTHOR("Tingting Lei <tingting.lei@mediatek.com>");
418 MODULE_DESCRIPTION("Bluetooth hardware control driver");
419 MODULE_LICENSE("GPL");