xref: /OK3568_Linux_fs/kernel/net/rfkill/rfkill-bt.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2012 ROCKCHIP, Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This software is licensed under the terms of the GNU General Public
5*4882a593Smuzhiyun  * License version 2, as published by the Free Software Foundation, and
6*4882a593Smuzhiyun  * may be copied, distributed, and modified under those terms.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful,
9*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11*4882a593Smuzhiyun  * GNU General Public License for more details.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun /* Rock-chips rfkill driver for bluetooth
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/platform_device.h>
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun #include <linux/rfkill.h>
22*4882a593Smuzhiyun #include <linux/init.h>
23*4882a593Smuzhiyun #include <linux/slab.h>
24*4882a593Smuzhiyun #include <linux/delay.h>
25*4882a593Smuzhiyun #include <linux/rfkill-bt.h>
26*4882a593Smuzhiyun #include <linux/rfkill-wlan.h>
27*4882a593Smuzhiyun #include <linux/wakelock.h>
28*4882a593Smuzhiyun #include <linux/interrupt.h>
29*4882a593Smuzhiyun #include <asm/irq.h>
30*4882a593Smuzhiyun #include <linux/suspend.h>
31*4882a593Smuzhiyun #include <linux/proc_fs.h>
32*4882a593Smuzhiyun #include <linux/uaccess.h>
33*4882a593Smuzhiyun #include <linux/gpio.h>
34*4882a593Smuzhiyun #include <linux/fs.h>
35*4882a593Smuzhiyun #include <dt-bindings/gpio/gpio.h>
36*4882a593Smuzhiyun #include <uapi/linux/rfkill.h>
37*4882a593Smuzhiyun #ifdef CONFIG_OF
38*4882a593Smuzhiyun #include <linux/of.h>
39*4882a593Smuzhiyun #include <linux/of_device.h>
40*4882a593Smuzhiyun #include <linux/of_gpio.h>
41*4882a593Smuzhiyun #endif
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #if 0
44*4882a593Smuzhiyun #define DBG(x...) pr_info("[BT_RFKILL]: " x)
45*4882a593Smuzhiyun #else
46*4882a593Smuzhiyun #define DBG(x...)
47*4882a593Smuzhiyun #endif
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #define LOG(x...) pr_info("[BT_RFKILL]: " x)
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #define BT_WAKEUP_TIMEOUT 10000
52*4882a593Smuzhiyun #define BT_IRQ_WAKELOCK_TIMEOUT (10 * 1000)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define BT_BLOCKED true
55*4882a593Smuzhiyun #define BT_UNBLOCK false
56*4882a593Smuzhiyun #define BT_SLEEP true
57*4882a593Smuzhiyun #define BT_WAKEUP false
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun enum {
60*4882a593Smuzhiyun 	IOMUX_FNORMAL = 0,
61*4882a593Smuzhiyun 	IOMUX_FGPIO,
62*4882a593Smuzhiyun 	IOMUX_FMUX,
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun struct rfkill_rk_data {
66*4882a593Smuzhiyun 	struct rfkill_rk_platform_data *pdata;
67*4882a593Smuzhiyun 	struct platform_device *pdev;
68*4882a593Smuzhiyun 	struct rfkill *rfkill_dev;
69*4882a593Smuzhiyun 	struct wake_lock bt_irq_wl;
70*4882a593Smuzhiyun 	struct delayed_work bt_sleep_delay_work;
71*4882a593Smuzhiyun 	int irq_req;
72*4882a593Smuzhiyun };
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun static struct rfkill_rk_data *g_rfkill = NULL;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun static const char bt_name[] =
77*4882a593Smuzhiyun #if defined(CONFIG_BCM4330)
78*4882a593Smuzhiyun #if defined(CONFIG_BT_MODULE_NH660)
79*4882a593Smuzhiyun 	"nh660"
80*4882a593Smuzhiyun #else
81*4882a593Smuzhiyun 	"bcm4330"
82*4882a593Smuzhiyun #endif
83*4882a593Smuzhiyun #elif defined(CONFIG_RK903)
84*4882a593Smuzhiyun #if defined(CONFIG_RKWIFI_26M)
85*4882a593Smuzhiyun 	"rk903_26M"
86*4882a593Smuzhiyun #else
87*4882a593Smuzhiyun 	"rk903"
88*4882a593Smuzhiyun #endif
89*4882a593Smuzhiyun #elif defined(CONFIG_BCM4329)
90*4882a593Smuzhiyun 	"bcm4329"
91*4882a593Smuzhiyun #elif defined(CONFIG_MV8787)
92*4882a593Smuzhiyun 	"mv8787"
93*4882a593Smuzhiyun #elif defined(CONFIG_AP6210)
94*4882a593Smuzhiyun #if defined(CONFIG_RKWIFI_26M)
95*4882a593Smuzhiyun 	"ap6210"
96*4882a593Smuzhiyun #else
97*4882a593Smuzhiyun 	"ap6210_24M"
98*4882a593Smuzhiyun #endif
99*4882a593Smuzhiyun #elif defined(CONFIG_AP6330)
100*4882a593Smuzhiyun 	"ap6330"
101*4882a593Smuzhiyun #elif defined(CONFIG_AP6476)
102*4882a593Smuzhiyun 	"ap6476"
103*4882a593Smuzhiyun #elif defined(CONFIG_AP6493)
104*4882a593Smuzhiyun 	"ap6493"
105*4882a593Smuzhiyun #elif defined(CONFIG_AP6441)
106*4882a593Smuzhiyun 	"ap6441"
107*4882a593Smuzhiyun #elif defined(CONFIG_AP6335)
108*4882a593Smuzhiyun 	"ap6335"
109*4882a593Smuzhiyun #elif defined(CONFIG_GB86302I)
110*4882a593Smuzhiyun 	"gb86302i"
111*4882a593Smuzhiyun #else
112*4882a593Smuzhiyun 	"bt_default"
113*4882a593Smuzhiyun #endif
114*4882a593Smuzhiyun 	;
115*4882a593Smuzhiyun 
rfkill_rk_wake_host_irq(int irq,void * dev)116*4882a593Smuzhiyun static irqreturn_t rfkill_rk_wake_host_irq(int irq, void *dev)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	struct rfkill_rk_data *rfkill = dev;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	LOG("BT_WAKE_HOST IRQ fired\n");
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	DBG("BT IRQ wakeup, request %dms wakelock\n", BT_IRQ_WAKELOCK_TIMEOUT);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	wake_lock_timeout(&rfkill->bt_irq_wl,
125*4882a593Smuzhiyun 			  msecs_to_jiffies(BT_IRQ_WAKELOCK_TIMEOUT));
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	return IRQ_HANDLED;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
rfkill_rk_setup_gpio(struct platform_device * pdev,struct rfkill_rk_gpio * gpio,const char * prefix,const char * name)130*4882a593Smuzhiyun static int rfkill_rk_setup_gpio(struct platform_device *pdev,
131*4882a593Smuzhiyun 				struct rfkill_rk_gpio *gpio, const char *prefix,
132*4882a593Smuzhiyun 				const char *name)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	if (gpio_is_valid(gpio->io)) {
135*4882a593Smuzhiyun 		int ret = 0;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 		sprintf(gpio->name, "%s_%s", prefix, name);
138*4882a593Smuzhiyun 		ret = devm_gpio_request(&pdev->dev, gpio->io, gpio->name);
139*4882a593Smuzhiyun 		if (ret) {
140*4882a593Smuzhiyun 			LOG("Failed to get %s gpio.\n", gpio->name);
141*4882a593Smuzhiyun 			return -1;
142*4882a593Smuzhiyun 		}
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
rfkill_rk_setup_wake_irq(struct rfkill_rk_data * rfkill,int flag)148*4882a593Smuzhiyun static int rfkill_rk_setup_wake_irq(struct rfkill_rk_data *rfkill, int flag)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	int ret = 0;
151*4882a593Smuzhiyun 	struct rfkill_rk_irq *irq = &rfkill->pdata->wake_host_irq;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	if (!flag) {
154*4882a593Smuzhiyun 		rfkill->irq_req = 0;
155*4882a593Smuzhiyun 		ret = rfkill_rk_setup_gpio(rfkill->pdev, &irq->gpio,
156*4882a593Smuzhiyun 					   rfkill->pdata->name, "wake_host");
157*4882a593Smuzhiyun 		if (ret)
158*4882a593Smuzhiyun 			goto fail1;
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 	if (gpio_is_valid(irq->gpio.io)) {
161*4882a593Smuzhiyun 		if (rfkill->irq_req) {
162*4882a593Smuzhiyun 			rfkill->irq_req = 0;
163*4882a593Smuzhiyun 			free_irq(irq->irq, rfkill);
164*4882a593Smuzhiyun 		}
165*4882a593Smuzhiyun 		LOG("Request irq for bt wakeup host\n");
166*4882a593Smuzhiyun 		irq->irq = gpio_to_irq(irq->gpio.io);
167*4882a593Smuzhiyun 		sprintf(irq->name, "%s_irq", irq->gpio.name);
168*4882a593Smuzhiyun 		ret = request_irq(irq->irq, rfkill_rk_wake_host_irq,
169*4882a593Smuzhiyun 				  (irq->gpio.enable == GPIO_ACTIVE_LOW) ?
170*4882a593Smuzhiyun 					  IRQF_TRIGGER_FALLING :
171*4882a593Smuzhiyun 					  IRQF_TRIGGER_RISING,
172*4882a593Smuzhiyun 				  irq->name, rfkill);
173*4882a593Smuzhiyun 		if (ret)
174*4882a593Smuzhiyun 			goto fail2;
175*4882a593Smuzhiyun 		rfkill->irq_req = 1;
176*4882a593Smuzhiyun 		LOG("** disable irq\n");
177*4882a593Smuzhiyun 		disable_irq(irq->irq);
178*4882a593Smuzhiyun 		ret = enable_irq_wake(irq->irq);
179*4882a593Smuzhiyun 		if (ret)
180*4882a593Smuzhiyun 			goto fail3;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	return ret;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun fail3:
186*4882a593Smuzhiyun 	free_irq(irq->irq, rfkill);
187*4882a593Smuzhiyun fail2:
188*4882a593Smuzhiyun 	gpio_free(irq->gpio.io);
189*4882a593Smuzhiyun fail1:
190*4882a593Smuzhiyun 	return ret;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
rfkill_rk_sleep_bt_internal(struct rfkill_rk_data * rfkill,bool sleep)193*4882a593Smuzhiyun static inline void rfkill_rk_sleep_bt_internal(struct rfkill_rk_data *rfkill,
194*4882a593Smuzhiyun 					       bool sleep)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	struct rfkill_rk_gpio *wake = &rfkill->pdata->wake_gpio;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	DBG("*** bt sleep: %d ***\n", sleep);
199*4882a593Smuzhiyun #ifndef CONFIG_BK3515A_COMBO
200*4882a593Smuzhiyun 	gpio_direction_output(wake->io, sleep ? !wake->enable : wake->enable);
201*4882a593Smuzhiyun #else
202*4882a593Smuzhiyun 	if (!sleep) {
203*4882a593Smuzhiyun 		DBG("HOST_UART0_TX pull down 10us\n");
204*4882a593Smuzhiyun 		if (rfkill_rk_setup_gpio(rfkill->pdev, wake,
205*4882a593Smuzhiyun 					 rfkill->pdata->name, "wake") != 0) {
206*4882a593Smuzhiyun 			return;
207*4882a593Smuzhiyun 		}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 		gpio_direction_output(wake->io, wake->enable);
210*4882a593Smuzhiyun 		usleep_range(10, 20);
211*4882a593Smuzhiyun 		gpio_direction_output(wake->io, !wake->enable);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 		gpio_free(wake->io);
214*4882a593Smuzhiyun 	}
215*4882a593Smuzhiyun #endif
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
rfkill_rk_delay_sleep_bt(struct work_struct * work)218*4882a593Smuzhiyun static void rfkill_rk_delay_sleep_bt(struct work_struct *work)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	struct rfkill_rk_data *rfkill = NULL;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	DBG("Enter %s\n", __func__);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	rfkill = container_of(work, struct rfkill_rk_data,
225*4882a593Smuzhiyun 			      bt_sleep_delay_work.work);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	rfkill_rk_sleep_bt_internal(rfkill, BT_SLEEP);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
rfkill_rk_sleep_bt(bool sleep)230*4882a593Smuzhiyun void rfkill_rk_sleep_bt(bool sleep)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	struct rfkill_rk_data *rfkill = g_rfkill;
233*4882a593Smuzhiyun 	struct rfkill_rk_gpio *wake;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	DBG("Enter %s\n", __func__);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	if (!rfkill) {
238*4882a593Smuzhiyun 		LOG("*** RFKILL is empty???\n");
239*4882a593Smuzhiyun 		return;
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	wake = &rfkill->pdata->wake_gpio;
243*4882a593Smuzhiyun 	if (!gpio_is_valid(wake->io)) {
244*4882a593Smuzhiyun 		DBG("*** Not support bt wakeup and sleep\n");
245*4882a593Smuzhiyun 		return;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	cancel_delayed_work_sync(&rfkill->bt_sleep_delay_work);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	rfkill_rk_sleep_bt_internal(rfkill, sleep);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun #ifdef CONFIG_BT_AUTOSLEEP
253*4882a593Smuzhiyun 	if (sleep == BT_WAKEUP) {
254*4882a593Smuzhiyun 		schedule_delayed_work(&rfkill->bt_sleep_delay_work,
255*4882a593Smuzhiyun 				      msecs_to_jiffies(BT_WAKEUP_TIMEOUT));
256*4882a593Smuzhiyun 	}
257*4882a593Smuzhiyun #endif
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun EXPORT_SYMBOL(rfkill_rk_sleep_bt);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun static int bt_power_state = 0;
rfkill_get_bt_power_state(int * power,bool * toggle)262*4882a593Smuzhiyun int rfkill_get_bt_power_state(int *power, bool *toggle)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	struct rfkill_rk_data *mrfkill = g_rfkill;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	if (!mrfkill) {
267*4882a593Smuzhiyun 		LOG("%s: rfkill-bt driver has not Successful initialized\n",
268*4882a593Smuzhiyun 		    __func__);
269*4882a593Smuzhiyun 		return -1;
270*4882a593Smuzhiyun 	}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	*toggle = mrfkill->pdata->power_toggle;
273*4882a593Smuzhiyun 	*power = bt_power_state;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return 0;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
rfkill_rk_set_power(void * data,bool blocked)278*4882a593Smuzhiyun static int rfkill_rk_set_power(void *data, bool blocked)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	struct rfkill_rk_data *rfkill = data;
281*4882a593Smuzhiyun 	struct rfkill_rk_gpio *wake_host = &rfkill->pdata->wake_host_irq.gpio;
282*4882a593Smuzhiyun 	struct rfkill_rk_gpio *poweron = &rfkill->pdata->poweron_gpio;
283*4882a593Smuzhiyun 	struct rfkill_rk_gpio *reset = &rfkill->pdata->reset_gpio;
284*4882a593Smuzhiyun 	struct rfkill_rk_gpio *rts = &rfkill->pdata->rts_gpio;
285*4882a593Smuzhiyun 	struct pinctrl *pinctrl = rfkill->pdata->pinctrl;
286*4882a593Smuzhiyun 	int wifi_power = 0;
287*4882a593Smuzhiyun 	bool toggle = false;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	DBG("Enter %s\n", __func__);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	DBG("Set blocked:%d\n", blocked);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	toggle = rfkill->pdata->power_toggle;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (toggle) {
296*4882a593Smuzhiyun 		if (rfkill_get_wifi_power_state(&wifi_power)) {
297*4882a593Smuzhiyun 			LOG("%s: cannot get wifi power state!\n", __func__);
298*4882a593Smuzhiyun 			return -1;
299*4882a593Smuzhiyun 		}
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	DBG("%s: toggle = %s\n", __func__, toggle ? "true" : "false");
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	if (!blocked) {
305*4882a593Smuzhiyun 		if (toggle) {
306*4882a593Smuzhiyun 			rfkill_set_wifi_bt_power(1);
307*4882a593Smuzhiyun 			msleep(100);
308*4882a593Smuzhiyun 		}
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 		rfkill_rk_sleep_bt(BT_WAKEUP); // ensure bt is wakeup
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 		if (gpio_is_valid(wake_host->io)) {
313*4882a593Smuzhiyun 			LOG("%s: set bt wake_host high!\n", __func__);
314*4882a593Smuzhiyun 			gpio_direction_output(wake_host->io, 1);
315*4882a593Smuzhiyun 			msleep(20);
316*4882a593Smuzhiyun 		}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 		if (gpio_is_valid(poweron->io)) {
319*4882a593Smuzhiyun 			if (gpio_get_value(poweron->io) == !poweron->enable) {
320*4882a593Smuzhiyun 				gpio_direction_output(poweron->io,
321*4882a593Smuzhiyun 						      !poweron->enable);
322*4882a593Smuzhiyun 				msleep(20);
323*4882a593Smuzhiyun 				gpio_direction_output(poweron->io,
324*4882a593Smuzhiyun 						      poweron->enable);
325*4882a593Smuzhiyun 				msleep(20);
326*4882a593Smuzhiyun 			}
327*4882a593Smuzhiyun 		}
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 		if (gpio_is_valid(reset->io)) {
330*4882a593Smuzhiyun 			if (gpio_get_value(reset->io) == !reset->enable) {
331*4882a593Smuzhiyun 				gpio_direction_output(reset->io,
332*4882a593Smuzhiyun 						      !reset->enable);
333*4882a593Smuzhiyun 				msleep(20);
334*4882a593Smuzhiyun 				gpio_direction_output(reset->io, reset->enable);
335*4882a593Smuzhiyun 			}
336*4882a593Smuzhiyun 		}
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 		if (gpio_is_valid(wake_host->io)) {
339*4882a593Smuzhiyun 			LOG("%s: set bt wake_host input!\n", __func__);
340*4882a593Smuzhiyun 			gpio_direction_input(wake_host->io);
341*4882a593Smuzhiyun 		}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 		if (pinctrl && gpio_is_valid(rts->io)) {
344*4882a593Smuzhiyun 			pinctrl_select_state(pinctrl, rts->gpio_state);
345*4882a593Smuzhiyun 			LOG("ENABLE UART_RTS\n");
346*4882a593Smuzhiyun 			gpio_direction_output(rts->io, rts->enable);
347*4882a593Smuzhiyun 			msleep(100);
348*4882a593Smuzhiyun 			LOG("DISABLE UART_RTS\n");
349*4882a593Smuzhiyun 			gpio_direction_output(rts->io, !rts->enable);
350*4882a593Smuzhiyun 			pinctrl_select_state(pinctrl, rts->default_state);
351*4882a593Smuzhiyun 		}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 		bt_power_state = 1;
354*4882a593Smuzhiyun 		LOG("bt turn on power\n");
355*4882a593Smuzhiyun 		rfkill_rk_setup_wake_irq(rfkill, 1);
356*4882a593Smuzhiyun 	} else {
357*4882a593Smuzhiyun 		if (gpio_is_valid(poweron->io)) {
358*4882a593Smuzhiyun 			if (gpio_get_value(poweron->io) == poweron->enable) {
359*4882a593Smuzhiyun 				gpio_direction_output(poweron->io,
360*4882a593Smuzhiyun 						      !poweron->enable);
361*4882a593Smuzhiyun 				msleep(20);
362*4882a593Smuzhiyun 			}
363*4882a593Smuzhiyun 		}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 		bt_power_state = 0;
366*4882a593Smuzhiyun 		LOG("bt shut off power\n");
367*4882a593Smuzhiyun 		if (gpio_is_valid(reset->io)) {
368*4882a593Smuzhiyun 			if (gpio_get_value(reset->io) == reset->enable) {
369*4882a593Smuzhiyun 				gpio_direction_output(reset->io,
370*4882a593Smuzhiyun 						      !reset->enable);
371*4882a593Smuzhiyun 				msleep(20);
372*4882a593Smuzhiyun 			}
373*4882a593Smuzhiyun 		}
374*4882a593Smuzhiyun 		if (toggle) {
375*4882a593Smuzhiyun 			if (!wifi_power) {
376*4882a593Smuzhiyun 				LOG("%s: bt will set vbat to low\n", __func__);
377*4882a593Smuzhiyun 				rfkill_set_wifi_bt_power(0);
378*4882a593Smuzhiyun 			} else {
379*4882a593Smuzhiyun 				LOG("%s: bt shouldn't control the vbat\n", __func__);
380*4882a593Smuzhiyun 			}
381*4882a593Smuzhiyun 		}
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	return 0;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
rfkill_rk_pm_prepare(struct device * dev)387*4882a593Smuzhiyun static int rfkill_rk_pm_prepare(struct device *dev)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun 	struct rfkill_rk_data *rfkill = g_rfkill;
390*4882a593Smuzhiyun 	struct rfkill_rk_gpio *rts;
391*4882a593Smuzhiyun 	struct rfkill_rk_irq *wake_host_irq;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	DBG("Enter %s\n", __func__);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (!rfkill)
396*4882a593Smuzhiyun 		return 0;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	rts = &rfkill->pdata->rts_gpio;
399*4882a593Smuzhiyun 	wake_host_irq = &rfkill->pdata->wake_host_irq;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	//To prevent uart to receive bt data when suspended
402*4882a593Smuzhiyun 	if (rfkill->pdata->pinctrl && gpio_is_valid(rts->io)) {
403*4882a593Smuzhiyun 		DBG("Disable UART_RTS\n");
404*4882a593Smuzhiyun 		pinctrl_select_state(rfkill->pdata->pinctrl, rts->gpio_state);
405*4882a593Smuzhiyun 		gpio_direction_output(rts->io, !rts->enable);
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun #ifdef CONFIG_BT_AUTOSLEEP
409*4882a593Smuzhiyun 	rfkill_rk_sleep_bt(BT_SLEEP);
410*4882a593Smuzhiyun #endif
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	// enable bt wakeup host
413*4882a593Smuzhiyun 	if (gpio_is_valid(wake_host_irq->gpio.io) && bt_power_state) {
414*4882a593Smuzhiyun 		DBG("enable irq for bt wakeup host\n");
415*4882a593Smuzhiyun 		enable_irq(wake_host_irq->irq);
416*4882a593Smuzhiyun 	}
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun #ifdef CONFIG_RFKILL_RESET
419*4882a593Smuzhiyun 	rfkill_init_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
420*4882a593Smuzhiyun 	rfkill_set_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
421*4882a593Smuzhiyun 	rfkill_set_hw_state(rfkill->rfkill_dev, false);
422*4882a593Smuzhiyun 	rfkill_rk_set_power(rfkill, BT_BLOCKED);
423*4882a593Smuzhiyun #endif
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	return 0;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun 
rfkill_rk_pm_complete(struct device * dev)428*4882a593Smuzhiyun static void rfkill_rk_pm_complete(struct device *dev)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun 	struct rfkill_rk_data *rfkill = g_rfkill;
431*4882a593Smuzhiyun 	struct rfkill_rk_irq *wake_host_irq;
432*4882a593Smuzhiyun 	struct rfkill_rk_gpio *rts;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	DBG("Enter %s\n", __func__);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	if (!rfkill)
437*4882a593Smuzhiyun 		return;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	wake_host_irq = &rfkill->pdata->wake_host_irq;
440*4882a593Smuzhiyun 	rts = &rfkill->pdata->rts_gpio;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	if (gpio_is_valid(wake_host_irq->gpio.io) && bt_power_state) {
443*4882a593Smuzhiyun 		LOG("** disable irq\n");
444*4882a593Smuzhiyun 		disable_irq(wake_host_irq->irq);
445*4882a593Smuzhiyun 	}
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	if (rfkill->pdata->pinctrl && gpio_is_valid(rts->io)) {
448*4882a593Smuzhiyun 		DBG("Enable UART_RTS\n");
449*4882a593Smuzhiyun 		gpio_direction_output(rts->io, rts->enable);
450*4882a593Smuzhiyun 		pinctrl_select_state(rfkill->pdata->pinctrl, rts->default_state);
451*4882a593Smuzhiyun 	}
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun static const struct rfkill_ops rfkill_rk_ops = {
455*4882a593Smuzhiyun 	.set_block = rfkill_rk_set_power,
456*4882a593Smuzhiyun };
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun #define PROC_DIR "bluetooth/sleep"
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun static struct proc_dir_entry *bluetooth_dir, *sleep_dir;
461*4882a593Smuzhiyun 
bluesleep_read_proc_lpm(struct file * file,char __user * buffer,size_t count,loff_t * data)462*4882a593Smuzhiyun static ssize_t bluesleep_read_proc_lpm(struct file *file, char __user *buffer,
463*4882a593Smuzhiyun 				       size_t count, loff_t *data)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun 	return sprintf(buffer, "unsupported to read\n");
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
bluesleep_write_proc_lpm(struct file * file,const char __user * buffer,size_t count,loff_t * data)468*4882a593Smuzhiyun static ssize_t bluesleep_write_proc_lpm(struct file *file,
469*4882a593Smuzhiyun 					const char __user *buffer, size_t count,
470*4882a593Smuzhiyun 					loff_t *data)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun 	return count;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
bluesleep_read_proc_btwrite(struct file * file,char __user * buffer,size_t count,loff_t * data)475*4882a593Smuzhiyun static ssize_t bluesleep_read_proc_btwrite(struct file *file,
476*4882a593Smuzhiyun 					   char __user *buffer, size_t count,
477*4882a593Smuzhiyun 					   loff_t *data)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun 	return sprintf(buffer, "unsupported to read\n");
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
bluesleep_write_proc_btwrite(struct file * file,const char __user * buffer,size_t count,loff_t * data)482*4882a593Smuzhiyun static ssize_t bluesleep_write_proc_btwrite(struct file *file,
483*4882a593Smuzhiyun 					    const char __user *buffer,
484*4882a593Smuzhiyun 					    size_t count, loff_t *data)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun 	char b;
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	if (count < 1)
489*4882a593Smuzhiyun 		return -EINVAL;
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	if (copy_from_user(&b, buffer, 1))
492*4882a593Smuzhiyun 		return -EFAULT;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	DBG("btwrite %c\n", b);
495*4882a593Smuzhiyun 	/* HCI_DEV_WRITE */
496*4882a593Smuzhiyun 	if (b != '0')
497*4882a593Smuzhiyun 		rfkill_rk_sleep_bt(BT_WAKEUP);
498*4882a593Smuzhiyun 	else
499*4882a593Smuzhiyun 		rfkill_rk_sleep_bt(BT_SLEEP);
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	return count;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun #ifdef CONFIG_OF
bluetooth_platdata_parse_dt(struct device * dev,struct rfkill_rk_platform_data * data)505*4882a593Smuzhiyun static int bluetooth_platdata_parse_dt(struct device *dev,
506*4882a593Smuzhiyun 				       struct rfkill_rk_platform_data *data)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	struct device_node *node = dev->of_node;
509*4882a593Smuzhiyun 	int gpio;
510*4882a593Smuzhiyun 	enum of_gpio_flags flags;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	if (!node)
513*4882a593Smuzhiyun 		return -ENODEV;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	memset(data, 0, sizeof(*data));
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	if (of_find_property(node, "wifi-bt-power-toggle", NULL)) {
518*4882a593Smuzhiyun 		data->power_toggle = true;
519*4882a593Smuzhiyun 		LOG("%s: get property wifi-bt-power-toggle.\n", __func__);
520*4882a593Smuzhiyun 	} else {
521*4882a593Smuzhiyun 		data->power_toggle = false;
522*4882a593Smuzhiyun 	}
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	gpio = of_get_named_gpio_flags(node, "uart_rts_gpios", 0, &flags);
525*4882a593Smuzhiyun 	if (gpio_is_valid(gpio)) {
526*4882a593Smuzhiyun 		data->rts_gpio.io = gpio;
527*4882a593Smuzhiyun 		data->rts_gpio.enable = (flags == GPIO_ACTIVE_HIGH) ? 1 : 0;
528*4882a593Smuzhiyun 		LOG("%s: get property: uart_rts_gpios = %d.\n", __func__, gpio);
529*4882a593Smuzhiyun 		data->pinctrl = devm_pinctrl_get(dev);
530*4882a593Smuzhiyun 		if (!IS_ERR(data->pinctrl)) {
531*4882a593Smuzhiyun 			data->rts_gpio.default_state =
532*4882a593Smuzhiyun 				pinctrl_lookup_state(data->pinctrl, "default");
533*4882a593Smuzhiyun 			data->rts_gpio.gpio_state =
534*4882a593Smuzhiyun 				pinctrl_lookup_state(data->pinctrl, "rts_gpio");
535*4882a593Smuzhiyun 		} else {
536*4882a593Smuzhiyun 			data->pinctrl = NULL;
537*4882a593Smuzhiyun 			LOG("%s: dts does't define the uart rts iomux.\n",
538*4882a593Smuzhiyun 			    __func__);
539*4882a593Smuzhiyun 			return -EINVAL;
540*4882a593Smuzhiyun 		}
541*4882a593Smuzhiyun 	} else {
542*4882a593Smuzhiyun 		data->pinctrl = NULL;
543*4882a593Smuzhiyun 		data->rts_gpio.io = -EINVAL;
544*4882a593Smuzhiyun 		LOG("%s: uart_rts_gpios is no-in-use.\n", __func__);
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	gpio = of_get_named_gpio_flags(node, "BT,power_gpio", 0, &flags);
548*4882a593Smuzhiyun 	if (gpio_is_valid(gpio)) {
549*4882a593Smuzhiyun 		data->poweron_gpio.io = gpio;
550*4882a593Smuzhiyun 		data->poweron_gpio.enable = (flags == GPIO_ACTIVE_HIGH) ? 1 : 0;
551*4882a593Smuzhiyun 		LOG("%s: get property: BT,power_gpio = %d.\n", __func__, gpio);
552*4882a593Smuzhiyun 	} else {
553*4882a593Smuzhiyun 		data->poweron_gpio.io = -1;
554*4882a593Smuzhiyun 	}
555*4882a593Smuzhiyun 	gpio = of_get_named_gpio_flags(node, "BT,reset_gpio", 0, &flags);
556*4882a593Smuzhiyun 	if (gpio_is_valid(gpio)) {
557*4882a593Smuzhiyun 		data->reset_gpio.io = gpio;
558*4882a593Smuzhiyun 		data->reset_gpio.enable = (flags == GPIO_ACTIVE_HIGH) ? 1 : 0;
559*4882a593Smuzhiyun 		LOG("%s: get property: BT,reset_gpio = %d.\n", __func__, gpio);
560*4882a593Smuzhiyun 	} else {
561*4882a593Smuzhiyun 		data->reset_gpio.io = -1;
562*4882a593Smuzhiyun 	}
563*4882a593Smuzhiyun 	gpio = of_get_named_gpio_flags(node, "BT,wake_gpio", 0, &flags);
564*4882a593Smuzhiyun 	if (gpio_is_valid(gpio)) {
565*4882a593Smuzhiyun 		data->wake_gpio.io = gpio;
566*4882a593Smuzhiyun 		data->wake_gpio.enable = (flags == GPIO_ACTIVE_HIGH) ? 1 : 0;
567*4882a593Smuzhiyun 		LOG("%s: get property: BT,wake_gpio = %d.\n", __func__, gpio);
568*4882a593Smuzhiyun 	} else {
569*4882a593Smuzhiyun 		data->wake_gpio.io = -1;
570*4882a593Smuzhiyun 	}
571*4882a593Smuzhiyun 	gpio = of_get_named_gpio_flags(node, "BT,wake_host_irq", 0, &flags);
572*4882a593Smuzhiyun 	if (gpio_is_valid(gpio)) {
573*4882a593Smuzhiyun 		data->wake_host_irq.gpio.io = gpio;
574*4882a593Smuzhiyun 		data->wake_host_irq.gpio.enable = flags;
575*4882a593Smuzhiyun 		LOG("%s: get property: BT,wake_host_irq = %d.\n", __func__,
576*4882a593Smuzhiyun 		    gpio);
577*4882a593Smuzhiyun 	} else {
578*4882a593Smuzhiyun 		data->wake_host_irq.gpio.io = -1;
579*4882a593Smuzhiyun 	}
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	data->ext_clk = devm_clk_get(dev, "ext_clock");
582*4882a593Smuzhiyun 	if (IS_ERR(data->ext_clk)) {
583*4882a593Smuzhiyun 		LOG("%s: clk_get failed!!!.\n", __func__);
584*4882a593Smuzhiyun 	} else {
585*4882a593Smuzhiyun 		clk_prepare_enable(data->ext_clk);
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun 	return 0;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun #endif //CONFIG_OF
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun static const struct proc_ops bluesleep_lpm = {
592*4882a593Smuzhiyun 	.proc_read = bluesleep_read_proc_lpm,
593*4882a593Smuzhiyun 	.proc_write = bluesleep_write_proc_lpm,
594*4882a593Smuzhiyun };
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun static const struct proc_ops bluesleep_btwrite = {
597*4882a593Smuzhiyun 	.proc_read = bluesleep_read_proc_btwrite,
598*4882a593Smuzhiyun 	.proc_write = bluesleep_write_proc_btwrite,
599*4882a593Smuzhiyun };
600*4882a593Smuzhiyun 
rfkill_rk_probe(struct platform_device * pdev)601*4882a593Smuzhiyun static int rfkill_rk_probe(struct platform_device *pdev)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun 	struct rfkill_rk_data *rfkill;
604*4882a593Smuzhiyun 	struct rfkill_rk_platform_data *pdata = pdev->dev.platform_data;
605*4882a593Smuzhiyun 	int ret = 0;
606*4882a593Smuzhiyun 	struct proc_dir_entry *ent;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	DBG("Enter %s\n", __func__);
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	if (!pdata) {
611*4882a593Smuzhiyun #ifdef CONFIG_OF
612*4882a593Smuzhiyun 		pdata = devm_kzalloc(&pdev->dev,
613*4882a593Smuzhiyun 				     sizeof(struct rfkill_rk_platform_data),
614*4882a593Smuzhiyun 				     GFP_KERNEL);
615*4882a593Smuzhiyun 		if (!pdata)
616*4882a593Smuzhiyun 			return -ENOMEM;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 		ret = bluetooth_platdata_parse_dt(&pdev->dev, pdata);
619*4882a593Smuzhiyun 		if (ret < 0) {
620*4882a593Smuzhiyun #endif
621*4882a593Smuzhiyun 			LOG("%s: No platform data specified\n", __func__);
622*4882a593Smuzhiyun 			return ret;
623*4882a593Smuzhiyun #ifdef CONFIG_OF
624*4882a593Smuzhiyun 		}
625*4882a593Smuzhiyun #endif
626*4882a593Smuzhiyun 	}
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	pdata->name = (char *)bt_name;
629*4882a593Smuzhiyun 	pdata->type = RFKILL_TYPE_BLUETOOTH;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL);
632*4882a593Smuzhiyun 	if (!rfkill)
633*4882a593Smuzhiyun 		return -ENOMEM;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	rfkill->pdata = pdata;
636*4882a593Smuzhiyun 	rfkill->pdev = pdev;
637*4882a593Smuzhiyun 	g_rfkill = rfkill;
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	bluetooth_dir = proc_mkdir("bluetooth", NULL);
640*4882a593Smuzhiyun 	if (!bluetooth_dir) {
641*4882a593Smuzhiyun 		LOG("Unable to create /proc/bluetooth directory");
642*4882a593Smuzhiyun 		return -ENOMEM;
643*4882a593Smuzhiyun 	}
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	sleep_dir = proc_mkdir("sleep", bluetooth_dir);
646*4882a593Smuzhiyun 	if (!sleep_dir) {
647*4882a593Smuzhiyun 		LOG("Unable to create /proc/%s directory", PROC_DIR);
648*4882a593Smuzhiyun 		return -ENOMEM;
649*4882a593Smuzhiyun 	}
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	/* read/write proc entries */
652*4882a593Smuzhiyun 	ent = proc_create("lpm", 0444, sleep_dir, &bluesleep_lpm);
653*4882a593Smuzhiyun 	if (!ent) {
654*4882a593Smuzhiyun 		LOG("Unable to create /proc/%s/lpm entry", PROC_DIR);
655*4882a593Smuzhiyun 		ret = -ENOMEM;
656*4882a593Smuzhiyun 		goto fail_alloc;
657*4882a593Smuzhiyun 	}
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	/* read/write proc entries */
660*4882a593Smuzhiyun 	ent = proc_create("btwrite", 0444, sleep_dir, &bluesleep_btwrite);
661*4882a593Smuzhiyun 	if (!ent) {
662*4882a593Smuzhiyun 		LOG("Unable to create /proc/%s/btwrite entry", PROC_DIR);
663*4882a593Smuzhiyun 		ret = -ENOMEM;
664*4882a593Smuzhiyun 		goto fail_alloc;
665*4882a593Smuzhiyun 	}
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	DBG("init gpio\n");
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	ret = rfkill_rk_setup_gpio(pdev, &pdata->poweron_gpio, pdata->name,
670*4882a593Smuzhiyun 				   "poweron");
671*4882a593Smuzhiyun 	if (ret)
672*4882a593Smuzhiyun 		goto fail_gpio;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	ret = rfkill_rk_setup_gpio(pdev, &pdata->reset_gpio, pdata->name,
675*4882a593Smuzhiyun 				   "reset");
676*4882a593Smuzhiyun 	if (ret)
677*4882a593Smuzhiyun 		goto fail_gpio;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	ret = rfkill_rk_setup_gpio(pdev, &pdata->wake_gpio, pdata->name,
680*4882a593Smuzhiyun 				   "wake");
681*4882a593Smuzhiyun 	if (ret)
682*4882a593Smuzhiyun 		goto fail_gpio;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	ret = rfkill_rk_setup_gpio(pdev, &pdata->rts_gpio, rfkill->pdata->name,
685*4882a593Smuzhiyun 				   "rts");
686*4882a593Smuzhiyun 	if (ret)
687*4882a593Smuzhiyun 		goto fail_gpio;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	wake_lock_init(&rfkill->bt_irq_wl, WAKE_LOCK_SUSPEND,
690*4882a593Smuzhiyun 		       "rfkill_rk_irq_wl");
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	ret = rfkill_rk_setup_wake_irq(rfkill, 0);
693*4882a593Smuzhiyun 	if (ret)
694*4882a593Smuzhiyun 		goto fail_setup_wake_irq;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	DBG("setup rfkill\n");
697*4882a593Smuzhiyun 	rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type,
698*4882a593Smuzhiyun 					  &rfkill_rk_ops, rfkill);
699*4882a593Smuzhiyun 	if (!rfkill->rfkill_dev)
700*4882a593Smuzhiyun 		goto fail_alloc;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	rfkill_init_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
703*4882a593Smuzhiyun 	rfkill_set_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
704*4882a593Smuzhiyun 	rfkill_set_hw_state(rfkill->rfkill_dev, false);
705*4882a593Smuzhiyun 	ret = rfkill_register(rfkill->rfkill_dev);
706*4882a593Smuzhiyun 	if (ret < 0)
707*4882a593Smuzhiyun 		goto fail_rfkill;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&rfkill->bt_sleep_delay_work,
710*4882a593Smuzhiyun 			  rfkill_rk_delay_sleep_bt);
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	//rfkill_rk_set_power(rfkill, BT_BLOCKED);
713*4882a593Smuzhiyun 	// bt turn off power
714*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->poweron_gpio.io)) {
715*4882a593Smuzhiyun 		gpio_direction_output(pdata->poweron_gpio.io,
716*4882a593Smuzhiyun 				      !pdata->poweron_gpio.enable);
717*4882a593Smuzhiyun 	}
718*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->reset_gpio.io)) {
719*4882a593Smuzhiyun 		gpio_direction_output(pdata->reset_gpio.io,
720*4882a593Smuzhiyun 				      !pdata->reset_gpio.enable);
721*4882a593Smuzhiyun 	}
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	platform_set_drvdata(pdev, rfkill);
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	LOG("%s device registered.\n", pdata->name);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	return 0;
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun fail_rfkill:
730*4882a593Smuzhiyun 	rfkill_destroy(rfkill->rfkill_dev);
731*4882a593Smuzhiyun fail_alloc:
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	remove_proc_entry("btwrite", sleep_dir);
734*4882a593Smuzhiyun 	remove_proc_entry("lpm", sleep_dir);
735*4882a593Smuzhiyun fail_setup_wake_irq:
736*4882a593Smuzhiyun 	wake_lock_destroy(&rfkill->bt_irq_wl);
737*4882a593Smuzhiyun fail_gpio:
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	g_rfkill = NULL;
740*4882a593Smuzhiyun 	return ret;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun 
rfkill_rk_remove(struct platform_device * pdev)743*4882a593Smuzhiyun static int rfkill_rk_remove(struct platform_device *pdev)
744*4882a593Smuzhiyun {
745*4882a593Smuzhiyun 	struct rfkill_rk_data *rfkill = platform_get_drvdata(pdev);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	LOG("Enter %s\n", __func__);
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	rfkill_unregister(rfkill->rfkill_dev);
750*4882a593Smuzhiyun 	rfkill_destroy(rfkill->rfkill_dev);
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	cancel_delayed_work_sync(&rfkill->bt_sleep_delay_work);
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	// free gpio
755*4882a593Smuzhiyun 	if (gpio_is_valid(rfkill->pdata->rts_gpio.io))
756*4882a593Smuzhiyun 		gpio_free(rfkill->pdata->rts_gpio.io);
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	if (gpio_is_valid(rfkill->pdata->wake_host_irq.gpio.io)) {
759*4882a593Smuzhiyun 		free_irq(rfkill->pdata->wake_host_irq.irq, rfkill);
760*4882a593Smuzhiyun #ifndef CONFIG_BK3515A_COMBO
761*4882a593Smuzhiyun 		gpio_free(rfkill->pdata->wake_host_irq.gpio.io);
762*4882a593Smuzhiyun #endif
763*4882a593Smuzhiyun 	}
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun #ifndef CONFIG_BK3515A_COMBO
766*4882a593Smuzhiyun 	if (gpio_is_valid(rfkill->pdata->wake_gpio.io))
767*4882a593Smuzhiyun 		gpio_free(rfkill->pdata->wake_gpio.io);
768*4882a593Smuzhiyun #endif
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	if (gpio_is_valid(rfkill->pdata->reset_gpio.io))
771*4882a593Smuzhiyun 		gpio_free(rfkill->pdata->reset_gpio.io);
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	if (gpio_is_valid(rfkill->pdata->poweron_gpio.io))
774*4882a593Smuzhiyun 		gpio_free(rfkill->pdata->poweron_gpio.io);
775*4882a593Smuzhiyun 	clk_disable_unprepare(rfkill->pdata->ext_clk);
776*4882a593Smuzhiyun 	wake_lock_destroy(&rfkill->bt_irq_wl);
777*4882a593Smuzhiyun 	g_rfkill = NULL;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	return 0;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun static const struct dev_pm_ops rfkill_rk_pm_ops = {
783*4882a593Smuzhiyun 	.prepare = rfkill_rk_pm_prepare,
784*4882a593Smuzhiyun 	.complete = rfkill_rk_pm_complete,
785*4882a593Smuzhiyun };
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun #ifdef CONFIG_OF
788*4882a593Smuzhiyun static struct of_device_id bt_platdata_of_match[] = {
789*4882a593Smuzhiyun 	{ .compatible = "bluetooth-platdata" },
790*4882a593Smuzhiyun 	{}
791*4882a593Smuzhiyun };
792*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, bt_platdata_of_match);
793*4882a593Smuzhiyun #endif //CONFIG_OF
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun static struct platform_driver rfkill_rk_driver = {
796*4882a593Smuzhiyun 	.probe = rfkill_rk_probe,
797*4882a593Smuzhiyun 	.remove = rfkill_rk_remove,
798*4882a593Smuzhiyun 	.driver = {
799*4882a593Smuzhiyun 		.name = "rfkill_bt",
800*4882a593Smuzhiyun 		.owner = THIS_MODULE,
801*4882a593Smuzhiyun 		.pm = &rfkill_rk_pm_ops,
802*4882a593Smuzhiyun         .of_match_table = of_match_ptr(bt_platdata_of_match),
803*4882a593Smuzhiyun 	},
804*4882a593Smuzhiyun };
805*4882a593Smuzhiyun 
rfkill_rk_init(void)806*4882a593Smuzhiyun static int __init rfkill_rk_init(void)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun 	int err;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	LOG("Enter %s\n", __func__);
811*4882a593Smuzhiyun 	err = rfkill_wlan_init();
812*4882a593Smuzhiyun 	if (err)
813*4882a593Smuzhiyun 		return err;
814*4882a593Smuzhiyun 	return platform_driver_register(&rfkill_rk_driver);
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun 
rfkill_rk_exit(void)817*4882a593Smuzhiyun static void __exit rfkill_rk_exit(void)
818*4882a593Smuzhiyun {
819*4882a593Smuzhiyun 	LOG("Enter %s\n", __func__);
820*4882a593Smuzhiyun 	platform_driver_unregister(&rfkill_rk_driver);
821*4882a593Smuzhiyun 	rfkill_wlan_exit();
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun module_init(rfkill_rk_init);
825*4882a593Smuzhiyun module_exit(rfkill_rk_exit);
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun MODULE_DESCRIPTION("rock-chips rfkill for Bluetooth v0.3");
828*4882a593Smuzhiyun MODULE_AUTHOR("cmy@rock-chips.com, gwl@rock-chips.com");
829*4882a593Smuzhiyun MODULE_LICENSE("GPL");
830