UPSTREAM: clk: rockchip: release io resource when failing to init clk
[firefly-linux-kernel-4.4.55.git] / drivers / mtk_wcn_bt / bt_plat_smdk.c
1 /* Copyright Statement:\r
2  *\r
3  * This software/firmware and related documentation ("MediaTek Software") are\r
4  * protected under relevant copyright laws. The information contained herein is\r
5  * confidential and proprietary to MediaTek Inc. and/or its licensors. Without\r
6  * the prior written permission of MediaTek inc. and/or its licensors, any\r
7  * reproduction, modification, use or disclosure of MediaTek Software, and\r
8  * information contained herein, in whole or in part, shall be strictly\r
9  * prohibited.\r
10  * \r
11  * MediaTek Inc. (C) 2010. All rights reserved.\r
12  * \r
13  * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES\r
14  * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")\r
15  * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER\r
16  * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL\r
17  * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED\r
18  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR\r
19  * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH\r
20  * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,\r
21  * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES\r
22  * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.\r
23  * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO\r
24  * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK\r
25  * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE\r
26  * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR\r
27  * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S\r
28  * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE\r
29  * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE\r
30  * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE\r
31  * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.\r
32  *\r
33  * The following software/firmware and/or related documentation ("MediaTek\r
34  * Software") have been modified by MediaTek Inc. All revisions are subject to\r
35  * any receiver's applicable license agreements with MediaTek Inc.\r
36  */\r
37 \r
38 #include <linux/module.h>\r
39 #include <linux/delay.h>\r
40 #include <linux/irq.h>\r
41 #include <linux/interrupt.h>\r
42 #include <linux/gpio.h>\r
43 #include <mach/gpio.h>\r
44 #include <mach/iomux.h>\r
45 //#include <plat/gpio-cfg.h>\r
46 \r
47 #include "bt_hwctl.h"\r
48 \r
49 extern int mt6622_suspend_flag;\r
50 \r
51 /****************************************************************************\r
52  *                           C O N S T A N T S                              *\r
53 *****************************************************************************/\r
54 #define MODULE_TAG         "[MT6622] "\r
55 \r
56 static int irq_num = -1;\r
57 \r
58 #ifdef CONFIG_ARCH_RK29\r
59     #define rk_mux_api_set(name,mode)      rk29_mux_api_set(name,mode)\r
60 #elif defined (CONFIG_ARCH_RK30)\r
61     #define rk_mux_api_set(name,mode)      rk30_mux_api_set(name,mode)\r
62 #else\r
63     #define rk_mux_api_set(name,mode)      rk30_mux_api_set(name,mode)\r
64 #endif\r
65 \r
66 static int irq_num;\r
67 // to avoid irq enable and disable not match\r
68 static unsigned int irq_mask;\r
69 //static spinlock_t bt_irq_lock;\r
70 \r
71 /****************************************************************************\r
72  *                       I R Q   F U N C T I O N S                          *\r
73 *****************************************************************************/\r
74 static int mt_bt_request_irq(void)\r
75 {\r
76     int iRet;\r
77     int trigger = IRQF_TRIGGER_RISING;\r
78     struct mt6622_platform_data *pdata = (struct mt6622_platform_data *)mt_bt_get_platform_data();\r
79                 \r
80     irq_mask = 0;\r
81     if(pdata->irq_gpio.enable == GPIO_LOW)\r
82         trigger = IRQF_TRIGGER_FALLING;\r
83     \r
84     iRet = request_irq(irq_num, mt_bt_eirq_handler, \r
85         trigger, "BT_INT_B", NULL);\r
86     if (iRet){\r
87         printk(KERN_ALERT MODULE_TAG "request_irq IRQ%d fails, errno %d\n", irq_num, iRet);\r
88     }\r
89     else{\r
90         printk(KERN_INFO MODULE_TAG "request_irq IRQ%d success\n", irq_num);\r
91         mt_bt_disable_irq();\r
92         /* enable irq when driver init complete, at hci_uart_open */\r
93     }\r
94     \r
95     return iRet;\r
96 }\r
97 \r
98 static void mt_bt_free_irq(void)\r
99 {\r
100     if(irq_num != -1)\r
101         free_irq(irq_num, NULL);\r
102     irq_mask = 0;\r
103         irq_num = -1;\r
104 }\r
105 \r
106 int mt6622_suspend(struct platform_device *pdev, pm_message_t state)\r
107 {\r
108     if(irq_num != -1) {\r
109         printk(KERN_INFO MODULE_TAG "mt6622_suspend\n");\r
110         mt6622_suspend_flag = 1;\r
111         enable_irq_wake(irq_num);\r
112     }\r
113         return 0;\r
114 }\r
115 \r
116 int mt6622_resume(struct platform_device *pdev)\r
117 {\r
118     if(irq_num != -1) {\r
119         printk(KERN_INFO MODULE_TAG "mt6622_resume\n");\r
120         disable_irq_wake(irq_num);\r
121     }\r
122         return 0;\r
123 }\r
124 \r
125 void mt_bt_enable_irq(void)\r
126 {\r
127     if (irq_mask){\r
128         irq_mask = 0;\r
129         enable_irq(irq_num);\r
130     }\r
131 }\r
132 EXPORT_SYMBOL(mt_bt_enable_irq);\r
133 \r
134 void mt_bt_disable_irq(void)\r
135 {\r
136     if (!irq_mask){\r
137         irq_mask = 1;\r
138         disable_irq_nosync(irq_num);\r
139     }\r
140 }\r
141 EXPORT_SYMBOL(mt_bt_disable_irq);\r
142 \r
143 /****************************************************************************\r
144  *                      P O W E R   C O N T R O L                           *\r
145 *****************************************************************************/\r
146 \r
147 int mt_bt_power_init(void)\r
148 {\r
149     struct mt6622_platform_data *pdata;\r
150     \r
151     printk(KERN_INFO MODULE_TAG "mt_bt_power_init\n");\r
152     \r
153     pdata = (struct mt6622_platform_data *)mt_bt_get_platform_data();\r
154     \r
155     if(pdata) {\r
156             \r
157             // PWR_EN and RESET\r
158             /* PWR_EN set to gpio output low */\r
159             if(pdata->power_gpio.io != INVALID_GPIO)\r
160                 gpio_direction_output(pdata->power_gpio.io, 0);\r
161             /* RESET set to gpio output low */\r
162             if(pdata->reset_gpio.io != INVALID_GPIO)\r
163                 gpio_direction_output(pdata->reset_gpio.io, 0);\r
164             msleep(200);\r
165             \r
166             /* PWR_EN pull up */\r
167             //if(pdata->power_gpio.io != INVALID_GPIO)\r
168             //  gpio_direction_output(pdata->power_gpio.io, 0);\r
169             //msleep(200);\r
170             /* RESET pull up */\r
171             if(pdata->reset_gpio.io != INVALID_GPIO)\r
172                 gpio_direction_output(pdata->reset_gpio.io, 1);\r
173             msleep(1000);\r
174             \r
175             //pdata->power_gpio.io = INVALID_GPIO;\r
176             pdata->reset_gpio.io = INVALID_GPIO;\r
177         }\r
178     \r
179     return 0;\r
180 }\r
181 EXPORT_SYMBOL(mt_bt_power_init);\r
182 \r
183 int mt_bt_power_on(void)\r
184 {\r
185     int error;\r
186     struct mt6622_platform_data *pdata;\r
187     \r
188     printk(KERN_INFO MODULE_TAG "mt_bt_power_on ++\n");\r
189     \r
190     pdata = (struct mt6622_platform_data *)mt_bt_get_platform_data();\r
191     \r
192     if(pdata) {\r
193             // UART TX/RX\r
194             \r
195             // PCMIN, PCMOUT, PCMCLK, PCMSYNC\r
196             \r
197             // EINT\r
198             //--s3c_gpio_cfgpin(GPIO_BT_EINT_PIN, S3C_GPIO_SFN(0));\r
199             //--s3c_gpio_setpull(GPIO_BT_EINT_PIN, S3C_GPIO_PULL_DOWN);\r
200             if(pdata->irq_gpio.io != INVALID_GPIO)\r
201                 gpio_direction_input(pdata->irq_gpio.io);\r
202             //gpio_pull_updown(pdata->irq_gpio->io, GPIOPullDown);\r
203             /* set to EINT mode */\r
204             //--s3c_gpio_cfgpin(GPIO_BT_EINT_PIN, S3C_GPIO_SFN(0xF));\r
205             /* get irq number */\r
206             if(pdata->irq_gpio.io != INVALID_GPIO)\r
207                 irq_num = gpio_to_irq(pdata->irq_gpio.io);\r
208             //mt_set_gpio_mode(GPIO_BT_EINT_PIN, GPIO_BT_EINT_PIN_M_GPIO);\r
209             //mt_set_gpio_pull_enable(GPIO_BT_EINT_PIN, 1);\r
210             //mt_set_gpio_pull_select(GPIO_BT_EINT_PIN, GPIO_PULL_DOWN);\r
211             //mt_set_gpio_mode(GPIO_BT_EINT_PIN, GPIO_BT_EINT_PIN_M_EINT);\r
212             \r
213             // 32k CLK\r
214             //mt_set_gpio_mode(GPIO_BT_CLK_PIN , GPIO_BT_CLK_PIN_M_CLK);\r
215             //mt_set_clock_output(GPIO_BT_CLK_PIN_CLK, CLK_SRC_F32K, 1);\r
216            \r
217          if(gpio_is_valid(pdata->rts_gpio.io)) {\r
218              printk(KERN_INFO MODULE_TAG "mt_bt_power_on rts iomux\n");\r
219              rk_mux_api_set(pdata->rts_gpio.iomux.name, pdata->rts_gpio.iomux.fgpio);\r
220              gpio_direction_output(pdata->rts_gpio.io, 0);\r
221          }         \r
222             \r
223             // PWR_EN and RESET\r
224             /* PWR_EN set to gpio output low */\r
225             if(pdata->power_gpio.io != INVALID_GPIO)\r
226                 gpio_direction_output(pdata->power_gpio.io, 0);\r
227             /* RESET set to gpio output low */\r
228             if(pdata->reset_gpio.io != INVALID_GPIO)\r
229                 gpio_direction_output(pdata->reset_gpio.io, 0);\r
230             msleep(200);\r
231             \r
232             /* PWR_EN pull up */\r
233             if(pdata->power_gpio.io != INVALID_GPIO)\r
234                 gpio_direction_output(pdata->power_gpio.io, 1);\r
235             msleep(200);\r
236             /* RESET pull up */\r
237             if(pdata->reset_gpio.io != INVALID_GPIO)\r
238                 gpio_direction_output(pdata->reset_gpio.io, 1);\r
239             msleep(1000);\r
240 \r
241         if(gpio_is_valid(pdata->rts_gpio.io)) {\r
242             rk_mux_api_set(pdata->rts_gpio.iomux.name, pdata->rts_gpio.iomux.fmux);\r
243         }\r
244             \r
245             error = mt_bt_request_irq();\r
246             if (error){\r
247                 if(pdata->power_gpio.io != INVALID_GPIO)\r
248                         gpio_direction_output(pdata->power_gpio.io, 0);\r
249                 if(pdata->reset_gpio.io != INVALID_GPIO)        \r
250                         gpio_direction_output(pdata->reset_gpio.io, 0);\r
251                 //--s3c_gpio_cfgpin(GPIO_BT_EINT_PIN, S3C_GPIO_SFN(1));\r
252                 if(pdata->irq_gpio.io != INVALID_GPIO)\r
253                         gpio_direction_output(pdata->irq_gpio.io, 0);\r
254                 return error;\r
255             }\r
256     }\r
257     \r
258     printk(KERN_INFO MODULE_TAG "mt_bt_power_on --\n");\r
259     \r
260     return 0;\r
261 }\r
262 \r
263 EXPORT_SYMBOL(mt_bt_power_on);\r
264 \r
265 \r
266 void mt_bt_power_off(void)\r
267 {\r
268     struct mt6622_platform_data *pdata;\r
269     pdata = (struct mt6622_platform_data *)mt_bt_get_platform_data();   \r
270         \r
271     printk(KERN_INFO MODULE_TAG "mt_bt_power_off ++\n");\r
272     \r
273     if(pdata) {\r
274             // PWR_EN and RESET\r
275             if(pdata->power_gpio.io != INVALID_GPIO)\r
276                 gpio_direction_output(pdata->power_gpio.io, 0);\r
277             if(pdata->reset_gpio.io != INVALID_GPIO)    \r
278                 gpio_direction_output(pdata->reset_gpio.io, 0);\r
279             \r
280             // EINT\r
281             //--s3c_gpio_cfgpin(GPIO_BT_EINT_PIN, S3C_GPIO_SFN(1));\r
282             if(pdata->irq_gpio.io != INVALID_GPIO)\r
283                 gpio_direction_output(pdata->irq_gpio.io, 0);\r
284             \r
285             mt_bt_free_irq();\r
286     }\r
287     \r
288     printk(KERN_INFO MODULE_TAG "mt_bt_power_off --\n");\r
289 }\r
290 \r
291 EXPORT_SYMBOL(mt_bt_power_off);\r