13d0407baSopenharmony_ci/*
23d0407baSopenharmony_ci * Copyright (C) 2012 ROCKCHIP, Inc.
33d0407baSopenharmony_ci *
43d0407baSopenharmony_ci * This software is licensed under the terms of the GNU General Public
53d0407baSopenharmony_ci * License version 2, as published by the Free Software Foundation, and
63d0407baSopenharmony_ci * may be copied, distributed, and modified under those terms.
73d0407baSopenharmony_ci *
83d0407baSopenharmony_ci * This program is distributed in the hope that it will be useful,
93d0407baSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
103d0407baSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
113d0407baSopenharmony_ci * GNU General Public License for more details.
123d0407baSopenharmony_ci *
133d0407baSopenharmony_ci */
143d0407baSopenharmony_ci/* Rock-chips rfkill driver for bluetooth
153d0407baSopenharmony_ci *
163d0407baSopenharmony_ci*/
173d0407baSopenharmony_ci
183d0407baSopenharmony_ci#include <linux/kernel.h>
193d0407baSopenharmony_ci#include <linux/platform_device.h>
203d0407baSopenharmony_ci#include <linux/module.h>
213d0407baSopenharmony_ci#include <linux/rfkill.h>
223d0407baSopenharmony_ci#include <linux/init.h>
233d0407baSopenharmony_ci#include <linux/slab.h>
243d0407baSopenharmony_ci#include <linux/delay.h>
253d0407baSopenharmony_ci#include <linux/rfkill-bt.h>
263d0407baSopenharmony_ci#include <linux/rfkill-wlan.h>
273d0407baSopenharmony_ci#include <linux/wakelock.h>
283d0407baSopenharmony_ci#include <linux/interrupt.h>
293d0407baSopenharmony_ci#include <asm/irq.h>
303d0407baSopenharmony_ci#include <linux/suspend.h>
313d0407baSopenharmony_ci#include <linux/proc_fs.h>
323d0407baSopenharmony_ci#include <linux/uaccess.h>
333d0407baSopenharmony_ci#include <linux/gpio.h>
343d0407baSopenharmony_ci#include <linux/fs.h>
353d0407baSopenharmony_ci#include <dt-bindings/gpio/gpio.h>
363d0407baSopenharmony_ci#include <uapi/linux/rfkill.h>
373d0407baSopenharmony_ci#ifdef CONFIG_OF
383d0407baSopenharmony_ci#include <linux/of.h>
393d0407baSopenharmony_ci#include <linux/of_device.h>
403d0407baSopenharmony_ci#include <linux/of_gpio.h>
413d0407baSopenharmony_ci#endif
423d0407baSopenharmony_ci
433d0407baSopenharmony_ci#if 0
443d0407baSopenharmony_ci#define DBG(x...) pr_info("[BT_RFKILL]: " x)
453d0407baSopenharmony_ci#else
463d0407baSopenharmony_ci#define DBG(x...)
473d0407baSopenharmony_ci#endif
483d0407baSopenharmony_ci
493d0407baSopenharmony_ci#define LOG(x...) pr_info("[BT_RFKILL]: " x)
503d0407baSopenharmony_ci
513d0407baSopenharmony_ci#define BT_WAKEUP_TIMEOUT 10000
523d0407baSopenharmony_ci#define BT_IRQ_WAKELOCK_TIMEOUT (10 * 1000)
533d0407baSopenharmony_ci
543d0407baSopenharmony_ci#define BT_BLOCKED true
553d0407baSopenharmony_ci#define BT_UNBLOCK false
563d0407baSopenharmony_ci#define BT_SLEEP true
573d0407baSopenharmony_ci#define BT_WAKEUP false
583d0407baSopenharmony_ci
593d0407baSopenharmony_cienum {
603d0407baSopenharmony_ci	IOMUX_FNORMAL = 0,
613d0407baSopenharmony_ci	IOMUX_FGPIO,
623d0407baSopenharmony_ci	IOMUX_FMUX,
633d0407baSopenharmony_ci};
643d0407baSopenharmony_ci
653d0407baSopenharmony_cistruct rfkill_rk_data {
663d0407baSopenharmony_ci	struct rfkill_rk_platform_data *pdata;
673d0407baSopenharmony_ci	struct platform_device *pdev;
683d0407baSopenharmony_ci	struct rfkill *rfkill_dev;
693d0407baSopenharmony_ci	struct wake_lock bt_irq_wl;
703d0407baSopenharmony_ci	struct delayed_work bt_sleep_delay_work;
713d0407baSopenharmony_ci	int irq_req;
723d0407baSopenharmony_ci};
733d0407baSopenharmony_ci
743d0407baSopenharmony_cistatic struct rfkill_rk_data *g_rfkill = NULL;
753d0407baSopenharmony_ci
763d0407baSopenharmony_cistatic const char bt_name[] =
773d0407baSopenharmony_ci#if defined(CONFIG_BCM4330)
783d0407baSopenharmony_ci#if defined(CONFIG_BT_MODULE_NH660)
793d0407baSopenharmony_ci	"nh660"
803d0407baSopenharmony_ci#else
813d0407baSopenharmony_ci	"bcm4330"
823d0407baSopenharmony_ci#endif
833d0407baSopenharmony_ci#elif defined(CONFIG_RK903)
843d0407baSopenharmony_ci#if defined(CONFIG_RKWIFI_26M)
853d0407baSopenharmony_ci	"rk903_26M"
863d0407baSopenharmony_ci#else
873d0407baSopenharmony_ci	"rk903"
883d0407baSopenharmony_ci#endif
893d0407baSopenharmony_ci#elif defined(CONFIG_BCM4329)
903d0407baSopenharmony_ci	"bcm4329"
913d0407baSopenharmony_ci#elif defined(CONFIG_MV8787)
923d0407baSopenharmony_ci	"mv8787"
933d0407baSopenharmony_ci#elif defined(CONFIG_AP6210)
943d0407baSopenharmony_ci#if defined(CONFIG_RKWIFI_26M)
953d0407baSopenharmony_ci	"ap6210"
963d0407baSopenharmony_ci#else
973d0407baSopenharmony_ci	"ap6210_24M"
983d0407baSopenharmony_ci#endif
993d0407baSopenharmony_ci#elif defined(CONFIG_AP6330)
1003d0407baSopenharmony_ci	"ap6330"
1013d0407baSopenharmony_ci#elif defined(CONFIG_AP6476)
1023d0407baSopenharmony_ci	"ap6476"
1033d0407baSopenharmony_ci#elif defined(CONFIG_AP6493)
1043d0407baSopenharmony_ci	"ap6493"
1053d0407baSopenharmony_ci#elif defined(CONFIG_AP6441)
1063d0407baSopenharmony_ci	"ap6441"
1073d0407baSopenharmony_ci#elif defined(CONFIG_AP6335)
1083d0407baSopenharmony_ci	"ap6335"
1093d0407baSopenharmony_ci#elif defined(CONFIG_GB86302I)
1103d0407baSopenharmony_ci	"gb86302i"
1113d0407baSopenharmony_ci#else
1123d0407baSopenharmony_ci	"bt_default"
1133d0407baSopenharmony_ci#endif
1143d0407baSopenharmony_ci	;
1153d0407baSopenharmony_ci
1163d0407baSopenharmony_cistatic irqreturn_t rfkill_rk_wake_host_irq(int irq, void *dev)
1173d0407baSopenharmony_ci{
1183d0407baSopenharmony_ci	struct rfkill_rk_data *rfkill = dev;
1193d0407baSopenharmony_ci
1203d0407baSopenharmony_ci	LOG("BT_WAKE_HOST IRQ fired\n");
1213d0407baSopenharmony_ci
1223d0407baSopenharmony_ci	DBG("BT IRQ wakeup, request %dms wakelock\n", BT_IRQ_WAKELOCK_TIMEOUT);
1233d0407baSopenharmony_ci
1243d0407baSopenharmony_ci	wake_lock_timeout(&rfkill->bt_irq_wl,
1253d0407baSopenharmony_ci			  msecs_to_jiffies(BT_IRQ_WAKELOCK_TIMEOUT));
1263d0407baSopenharmony_ci
1273d0407baSopenharmony_ci	return IRQ_HANDLED;
1283d0407baSopenharmony_ci}
1293d0407baSopenharmony_ci
1303d0407baSopenharmony_cistatic int rfkill_rk_setup_gpio(struct platform_device *pdev,
1313d0407baSopenharmony_ci				struct rfkill_rk_gpio *gpio, const char *prefix,
1323d0407baSopenharmony_ci				const char *name)
1333d0407baSopenharmony_ci{
1343d0407baSopenharmony_ci	if (gpio_is_valid(gpio->io)) {
1353d0407baSopenharmony_ci		int ret = 0;
1363d0407baSopenharmony_ci
1373d0407baSopenharmony_ci		sprintf(gpio->name, "%s_%s", prefix, name);
1383d0407baSopenharmony_ci		ret = devm_gpio_request(&pdev->dev, gpio->io, gpio->name);
1393d0407baSopenharmony_ci		if (ret) {
1403d0407baSopenharmony_ci			LOG("Failed to get %s gpio.\n", gpio->name);
1413d0407baSopenharmony_ci			return -1;
1423d0407baSopenharmony_ci		}
1433d0407baSopenharmony_ci	}
1443d0407baSopenharmony_ci
1453d0407baSopenharmony_ci	return 0;
1463d0407baSopenharmony_ci}
1473d0407baSopenharmony_ci
1483d0407baSopenharmony_cistatic int rfkill_rk_setup_wake_irq(struct rfkill_rk_data *rfkill, int flag)
1493d0407baSopenharmony_ci{
1503d0407baSopenharmony_ci	int ret = 0;
1513d0407baSopenharmony_ci	struct rfkill_rk_irq *irq = &rfkill->pdata->wake_host_irq;
1523d0407baSopenharmony_ci
1533d0407baSopenharmony_ci	if (!flag) {
1543d0407baSopenharmony_ci		rfkill->irq_req = 0;
1553d0407baSopenharmony_ci		ret = rfkill_rk_setup_gpio(rfkill->pdev, &irq->gpio,
1563d0407baSopenharmony_ci					   rfkill->pdata->name, "wake_host");
1573d0407baSopenharmony_ci		if (ret)
1583d0407baSopenharmony_ci			goto fail1;
1593d0407baSopenharmony_ci	}
1603d0407baSopenharmony_ci	if (gpio_is_valid(irq->gpio.io)) {
1613d0407baSopenharmony_ci		if (rfkill->irq_req) {
1623d0407baSopenharmony_ci			rfkill->irq_req = 0;
1633d0407baSopenharmony_ci			free_irq(irq->irq, rfkill);
1643d0407baSopenharmony_ci		}
1653d0407baSopenharmony_ci		LOG("Request irq for bt wakeup host\n");
1663d0407baSopenharmony_ci		irq->irq = gpio_to_irq(irq->gpio.io);
1673d0407baSopenharmony_ci		sprintf(irq->name, "%s_irq", irq->gpio.name);
1683d0407baSopenharmony_ci		ret = request_irq(irq->irq, rfkill_rk_wake_host_irq,
1693d0407baSopenharmony_ci				  (irq->gpio.enable == GPIO_ACTIVE_LOW) ?
1703d0407baSopenharmony_ci					  IRQF_TRIGGER_FALLING :
1713d0407baSopenharmony_ci					  IRQF_TRIGGER_RISING,
1723d0407baSopenharmony_ci				  irq->name, rfkill);
1733d0407baSopenharmony_ci		if (ret)
1743d0407baSopenharmony_ci			goto fail2;
1753d0407baSopenharmony_ci		rfkill->irq_req = 1;
1763d0407baSopenharmony_ci		LOG("** disable irq\n");
1773d0407baSopenharmony_ci		disable_irq(irq->irq);
1783d0407baSopenharmony_ci		ret = enable_irq_wake(irq->irq);
1793d0407baSopenharmony_ci		if (ret)
1803d0407baSopenharmony_ci			goto fail3;
1813d0407baSopenharmony_ci	}
1823d0407baSopenharmony_ci
1833d0407baSopenharmony_ci	return ret;
1843d0407baSopenharmony_ci
1853d0407baSopenharmony_cifail3:
1863d0407baSopenharmony_ci	free_irq(irq->irq, rfkill);
1873d0407baSopenharmony_cifail2:
1883d0407baSopenharmony_ci	gpio_free(irq->gpio.io);
1893d0407baSopenharmony_cifail1:
1903d0407baSopenharmony_ci	return ret;
1913d0407baSopenharmony_ci}
1923d0407baSopenharmony_ci
1933d0407baSopenharmony_cistatic inline void rfkill_rk_sleep_bt_internal(struct rfkill_rk_data *rfkill,
1943d0407baSopenharmony_ci					       bool sleep)
1953d0407baSopenharmony_ci{
1963d0407baSopenharmony_ci	struct rfkill_rk_gpio *wake = &rfkill->pdata->wake_gpio;
1973d0407baSopenharmony_ci
1983d0407baSopenharmony_ci	DBG("*** bt sleep: %d ***\n", sleep);
1993d0407baSopenharmony_ci#ifndef CONFIG_BK3515A_COMBO
2003d0407baSopenharmony_ci	gpio_direction_output(wake->io, sleep ? !wake->enable : wake->enable);
2013d0407baSopenharmony_ci#else
2023d0407baSopenharmony_ci	if (!sleep) {
2033d0407baSopenharmony_ci		DBG("HOST_UART0_TX pull down 10us\n");
2043d0407baSopenharmony_ci		if (rfkill_rk_setup_gpio(rfkill->pdev, wake,
2053d0407baSopenharmony_ci					 rfkill->pdata->name, "wake") != 0) {
2063d0407baSopenharmony_ci			return;
2073d0407baSopenharmony_ci		}
2083d0407baSopenharmony_ci
2093d0407baSopenharmony_ci		gpio_direction_output(wake->io, wake->enable);
2103d0407baSopenharmony_ci		usleep_range(10, 20);
2113d0407baSopenharmony_ci		gpio_direction_output(wake->io, !wake->enable);
2123d0407baSopenharmony_ci
2133d0407baSopenharmony_ci		gpio_free(wake->io);
2143d0407baSopenharmony_ci	}
2153d0407baSopenharmony_ci#endif
2163d0407baSopenharmony_ci}
2173d0407baSopenharmony_ci
2183d0407baSopenharmony_cistatic void rfkill_rk_delay_sleep_bt(struct work_struct *work)
2193d0407baSopenharmony_ci{
2203d0407baSopenharmony_ci	struct rfkill_rk_data *rfkill = NULL;
2213d0407baSopenharmony_ci
2223d0407baSopenharmony_ci	DBG("Enter %s\n", __func__);
2233d0407baSopenharmony_ci
2243d0407baSopenharmony_ci	rfkill = container_of(work, struct rfkill_rk_data,
2253d0407baSopenharmony_ci			      bt_sleep_delay_work.work);
2263d0407baSopenharmony_ci
2273d0407baSopenharmony_ci	rfkill_rk_sleep_bt_internal(rfkill, BT_SLEEP);
2283d0407baSopenharmony_ci}
2293d0407baSopenharmony_ci
2303d0407baSopenharmony_civoid rfkill_rk_sleep_bt(bool sleep)
2313d0407baSopenharmony_ci{
2323d0407baSopenharmony_ci	struct rfkill_rk_data *rfkill = g_rfkill;
2333d0407baSopenharmony_ci	struct rfkill_rk_gpio *wake;
2343d0407baSopenharmony_ci
2353d0407baSopenharmony_ci	DBG("Enter %s\n", __func__);
2363d0407baSopenharmony_ci
2373d0407baSopenharmony_ci	if (!rfkill) {
2383d0407baSopenharmony_ci		LOG("*** RFKILL is empty???\n");
2393d0407baSopenharmony_ci		return;
2403d0407baSopenharmony_ci	}
2413d0407baSopenharmony_ci
2423d0407baSopenharmony_ci	wake = &rfkill->pdata->wake_gpio;
2433d0407baSopenharmony_ci	if (!gpio_is_valid(wake->io)) {
2443d0407baSopenharmony_ci		DBG("*** Not support bt wakeup and sleep\n");
2453d0407baSopenharmony_ci		return;
2463d0407baSopenharmony_ci	}
2473d0407baSopenharmony_ci
2483d0407baSopenharmony_ci	cancel_delayed_work_sync(&rfkill->bt_sleep_delay_work);
2493d0407baSopenharmony_ci
2503d0407baSopenharmony_ci	rfkill_rk_sleep_bt_internal(rfkill, sleep);
2513d0407baSopenharmony_ci
2523d0407baSopenharmony_ci#ifdef CONFIG_BT_AUTOSLEEP
2533d0407baSopenharmony_ci	if (sleep == BT_WAKEUP) {
2543d0407baSopenharmony_ci		schedule_delayed_work(&rfkill->bt_sleep_delay_work,
2553d0407baSopenharmony_ci				      msecs_to_jiffies(BT_WAKEUP_TIMEOUT));
2563d0407baSopenharmony_ci	}
2573d0407baSopenharmony_ci#endif
2583d0407baSopenharmony_ci}
2593d0407baSopenharmony_ciEXPORT_SYMBOL(rfkill_rk_sleep_bt);
2603d0407baSopenharmony_ci
2613d0407baSopenharmony_cistatic int bt_power_state = 0;
2623d0407baSopenharmony_ciint rfkill_get_bt_power_state(int *power, bool *toggle)
2633d0407baSopenharmony_ci{
2643d0407baSopenharmony_ci	struct rfkill_rk_data *mrfkill = g_rfkill;
2653d0407baSopenharmony_ci
2663d0407baSopenharmony_ci	if (!mrfkill) {
2673d0407baSopenharmony_ci		LOG("%s: rfkill-bt driver has not Successful initialized\n",
2683d0407baSopenharmony_ci		    __func__);
2693d0407baSopenharmony_ci		return -1;
2703d0407baSopenharmony_ci	}
2713d0407baSopenharmony_ci
2723d0407baSopenharmony_ci	*toggle = mrfkill->pdata->power_toggle;
2733d0407baSopenharmony_ci	*power = bt_power_state;
2743d0407baSopenharmony_ci
2753d0407baSopenharmony_ci	return 0;
2763d0407baSopenharmony_ci}
2773d0407baSopenharmony_ci
2783d0407baSopenharmony_cistatic int rfkill_rk_set_power(void *data, bool blocked)
2793d0407baSopenharmony_ci{
2803d0407baSopenharmony_ci	struct rfkill_rk_data *rfkill = data;
2813d0407baSopenharmony_ci	struct rfkill_rk_gpio *wake_host = &rfkill->pdata->wake_host_irq.gpio;
2823d0407baSopenharmony_ci	struct rfkill_rk_gpio *poweron = &rfkill->pdata->poweron_gpio;
2833d0407baSopenharmony_ci	struct rfkill_rk_gpio *reset = &rfkill->pdata->reset_gpio;
2843d0407baSopenharmony_ci	struct rfkill_rk_gpio *rts = &rfkill->pdata->rts_gpio;
2853d0407baSopenharmony_ci	struct pinctrl *pinctrl = rfkill->pdata->pinctrl;
2863d0407baSopenharmony_ci	int wifi_power = 0;
2873d0407baSopenharmony_ci	bool toggle = false;
2883d0407baSopenharmony_ci
2893d0407baSopenharmony_ci	DBG("Enter %s\n", __func__);
2903d0407baSopenharmony_ci
2913d0407baSopenharmony_ci	DBG("Set blocked:%d\n", blocked);
2923d0407baSopenharmony_ci
2933d0407baSopenharmony_ci	toggle = rfkill->pdata->power_toggle;
2943d0407baSopenharmony_ci
2953d0407baSopenharmony_ci	if (toggle) {
2963d0407baSopenharmony_ci		if (rfkill_get_wifi_power_state(&wifi_power)) {
2973d0407baSopenharmony_ci			LOG("%s: cannot get wifi power state!\n", __func__);
2983d0407baSopenharmony_ci			return -1;
2993d0407baSopenharmony_ci		}
3003d0407baSopenharmony_ci	}
3013d0407baSopenharmony_ci
3023d0407baSopenharmony_ci	DBG("%s: toggle = %s\n", __func__, toggle ? "true" : "false");
3033d0407baSopenharmony_ci
3043d0407baSopenharmony_ci	if (!blocked) {
3053d0407baSopenharmony_ci		if (toggle) {
3063d0407baSopenharmony_ci			rfkill_set_wifi_bt_power(1);
3073d0407baSopenharmony_ci			msleep(100);
3083d0407baSopenharmony_ci		}
3093d0407baSopenharmony_ci
3103d0407baSopenharmony_ci		rfkill_rk_sleep_bt(BT_WAKEUP); // ensure bt is wakeup
3113d0407baSopenharmony_ci
3123d0407baSopenharmony_ci		if (gpio_is_valid(wake_host->io)) {
3133d0407baSopenharmony_ci			LOG("%s: set bt wake_host high!\n", __func__);
3143d0407baSopenharmony_ci			gpio_direction_output(wake_host->io, 1);
3153d0407baSopenharmony_ci			msleep(20);
3163d0407baSopenharmony_ci		}
3173d0407baSopenharmony_ci
3183d0407baSopenharmony_ci		if (gpio_is_valid(poweron->io)) {
3193d0407baSopenharmony_ci			if (gpio_get_value(poweron->io) == !poweron->enable) {
3203d0407baSopenharmony_ci				gpio_direction_output(poweron->io,
3213d0407baSopenharmony_ci						      !poweron->enable);
3223d0407baSopenharmony_ci				msleep(20);
3233d0407baSopenharmony_ci				gpio_direction_output(poweron->io,
3243d0407baSopenharmony_ci						      poweron->enable);
3253d0407baSopenharmony_ci				msleep(20);
3263d0407baSopenharmony_ci				if (gpio_is_valid(wake_host->io))
3273d0407baSopenharmony_ci					gpio_direction_input(wake_host->io);
3283d0407baSopenharmony_ci			}
3293d0407baSopenharmony_ci		}
3303d0407baSopenharmony_ci
3313d0407baSopenharmony_ci		if (gpio_is_valid(reset->io)) {
3323d0407baSopenharmony_ci			if (gpio_get_value(reset->io) == !reset->enable) {
3333d0407baSopenharmony_ci				gpio_direction_output(reset->io,
3343d0407baSopenharmony_ci						      !reset->enable);
3353d0407baSopenharmony_ci				msleep(20);
3363d0407baSopenharmony_ci				gpio_direction_output(reset->io, reset->enable);
3373d0407baSopenharmony_ci			}
3383d0407baSopenharmony_ci		}
3393d0407baSopenharmony_ci
3403d0407baSopenharmony_ci		if (pinctrl && gpio_is_valid(rts->io)) {
3413d0407baSopenharmony_ci			pinctrl_select_state(pinctrl, rts->gpio_state);
3423d0407baSopenharmony_ci			LOG("ENABLE UART_RTS\n");
3433d0407baSopenharmony_ci			gpio_direction_output(rts->io, rts->enable);
3443d0407baSopenharmony_ci			msleep(100);
3453d0407baSopenharmony_ci			LOG("DISABLE UART_RTS\n");
3463d0407baSopenharmony_ci			gpio_direction_output(rts->io, !rts->enable);
3473d0407baSopenharmony_ci			pinctrl_select_state(pinctrl, rts->default_state);
3483d0407baSopenharmony_ci		}
3493d0407baSopenharmony_ci
3503d0407baSopenharmony_ci		bt_power_state = 1;
3513d0407baSopenharmony_ci		LOG("bt turn on power\n");
3523d0407baSopenharmony_ci		rfkill_rk_setup_wake_irq(rfkill, 1);
3533d0407baSopenharmony_ci	} else {
3543d0407baSopenharmony_ci		if (gpio_is_valid(poweron->io)) {
3553d0407baSopenharmony_ci			if (gpio_get_value(poweron->io) == poweron->enable) {
3563d0407baSopenharmony_ci				gpio_direction_output(poweron->io,
3573d0407baSopenharmony_ci						      !poweron->enable);
3583d0407baSopenharmony_ci				msleep(20);
3593d0407baSopenharmony_ci			}
3603d0407baSopenharmony_ci		}
3613d0407baSopenharmony_ci
3623d0407baSopenharmony_ci		bt_power_state = 0;
3633d0407baSopenharmony_ci		LOG("bt shut off power\n");
3643d0407baSopenharmony_ci		if (gpio_is_valid(reset->io)) {
3653d0407baSopenharmony_ci			if (gpio_get_value(reset->io) == reset->enable) {
3663d0407baSopenharmony_ci				gpio_direction_output(reset->io,
3673d0407baSopenharmony_ci						      !reset->enable);
3683d0407baSopenharmony_ci				msleep(20);
3693d0407baSopenharmony_ci			}
3703d0407baSopenharmony_ci		}
3713d0407baSopenharmony_ci		if (toggle) {
3723d0407baSopenharmony_ci			if (!wifi_power) {
3733d0407baSopenharmony_ci				LOG("%s: bt will set vbat to low\n", __func__);
3743d0407baSopenharmony_ci				rfkill_set_wifi_bt_power(0);
3753d0407baSopenharmony_ci			} else {
3763d0407baSopenharmony_ci				LOG("%s: bt shouldn't control the vbat\n", __func__);
3773d0407baSopenharmony_ci			}
3783d0407baSopenharmony_ci		}
3793d0407baSopenharmony_ci	}
3803d0407baSopenharmony_ci
3813d0407baSopenharmony_ci	return 0;
3823d0407baSopenharmony_ci}
3833d0407baSopenharmony_ci
3843d0407baSopenharmony_cistatic int rfkill_rk_pm_prepare(struct device *dev)
3853d0407baSopenharmony_ci{
3863d0407baSopenharmony_ci	struct rfkill_rk_data *rfkill = g_rfkill;
3873d0407baSopenharmony_ci	struct rfkill_rk_gpio *rts;
3883d0407baSopenharmony_ci	struct rfkill_rk_irq *wake_host_irq;
3893d0407baSopenharmony_ci
3903d0407baSopenharmony_ci	DBG("Enter %s\n", __func__);
3913d0407baSopenharmony_ci
3923d0407baSopenharmony_ci	if (!rfkill)
3933d0407baSopenharmony_ci		return 0;
3943d0407baSopenharmony_ci
3953d0407baSopenharmony_ci	rts = &rfkill->pdata->rts_gpio;
3963d0407baSopenharmony_ci	wake_host_irq = &rfkill->pdata->wake_host_irq;
3973d0407baSopenharmony_ci
3983d0407baSopenharmony_ci	//To prevent uart to receive bt data when suspended
3993d0407baSopenharmony_ci	if (rfkill->pdata->pinctrl && gpio_is_valid(rts->io)) {
4003d0407baSopenharmony_ci		DBG("Disable UART_RTS\n");
4013d0407baSopenharmony_ci		pinctrl_select_state(rfkill->pdata->pinctrl, rts->gpio_state);
4023d0407baSopenharmony_ci		gpio_direction_output(rts->io, !rts->enable);
4033d0407baSopenharmony_ci	}
4043d0407baSopenharmony_ci
4053d0407baSopenharmony_ci#ifdef CONFIG_BT_AUTOSLEEP
4063d0407baSopenharmony_ci	rfkill_rk_sleep_bt(BT_SLEEP);
4073d0407baSopenharmony_ci#endif
4083d0407baSopenharmony_ci
4093d0407baSopenharmony_ci	// enable bt wakeup host
4103d0407baSopenharmony_ci	if (gpio_is_valid(wake_host_irq->gpio.io) && bt_power_state) {
4113d0407baSopenharmony_ci		DBG("enable irq for bt wakeup host\n");
4123d0407baSopenharmony_ci		enable_irq(wake_host_irq->irq);
4133d0407baSopenharmony_ci	}
4143d0407baSopenharmony_ci
4153d0407baSopenharmony_ci#ifdef CONFIG_RFKILL_RESET
4163d0407baSopenharmony_ci	rfkill_init_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
4173d0407baSopenharmony_ci	rfkill_set_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
4183d0407baSopenharmony_ci	rfkill_set_hw_state(rfkill->rfkill_dev, false);
4193d0407baSopenharmony_ci	rfkill_rk_set_power(rfkill, BT_BLOCKED);
4203d0407baSopenharmony_ci#endif
4213d0407baSopenharmony_ci
4223d0407baSopenharmony_ci	return 0;
4233d0407baSopenharmony_ci}
4243d0407baSopenharmony_ci
4253d0407baSopenharmony_cistatic void rfkill_rk_pm_complete(struct device *dev)
4263d0407baSopenharmony_ci{
4273d0407baSopenharmony_ci	struct rfkill_rk_data *rfkill = g_rfkill;
4283d0407baSopenharmony_ci	struct rfkill_rk_irq *wake_host_irq;
4293d0407baSopenharmony_ci	struct rfkill_rk_gpio *rts;
4303d0407baSopenharmony_ci
4313d0407baSopenharmony_ci	DBG("Enter %s\n", __func__);
4323d0407baSopenharmony_ci
4333d0407baSopenharmony_ci	if (!rfkill)
4343d0407baSopenharmony_ci		return;
4353d0407baSopenharmony_ci
4363d0407baSopenharmony_ci	wake_host_irq = &rfkill->pdata->wake_host_irq;
4373d0407baSopenharmony_ci	rts = &rfkill->pdata->rts_gpio;
4383d0407baSopenharmony_ci
4393d0407baSopenharmony_ci	if (gpio_is_valid(wake_host_irq->gpio.io) && bt_power_state) {
4403d0407baSopenharmony_ci		LOG("** disable irq\n");
4413d0407baSopenharmony_ci		disable_irq(wake_host_irq->irq);
4423d0407baSopenharmony_ci	}
4433d0407baSopenharmony_ci
4443d0407baSopenharmony_ci	if (rfkill->pdata->pinctrl && gpio_is_valid(rts->io)) {
4453d0407baSopenharmony_ci		DBG("Enable UART_RTS\n");
4463d0407baSopenharmony_ci		gpio_direction_output(rts->io, rts->enable);
4473d0407baSopenharmony_ci		pinctrl_select_state(rfkill->pdata->pinctrl, rts->default_state);
4483d0407baSopenharmony_ci	}
4493d0407baSopenharmony_ci}
4503d0407baSopenharmony_ci
4513d0407baSopenharmony_cistatic const struct rfkill_ops rfkill_rk_ops = {
4523d0407baSopenharmony_ci	.set_block = rfkill_rk_set_power,
4533d0407baSopenharmony_ci};
4543d0407baSopenharmony_ci
4553d0407baSopenharmony_ci#define PROC_DIR "bluetooth/sleep"
4563d0407baSopenharmony_ci
4573d0407baSopenharmony_cistatic struct proc_dir_entry *bluetooth_dir, *sleep_dir;
4583d0407baSopenharmony_ci
4593d0407baSopenharmony_cistatic ssize_t bluesleep_read_proc_lpm(struct file *file, char __user *buffer,
4603d0407baSopenharmony_ci				       size_t count, loff_t *data)
4613d0407baSopenharmony_ci{
4623d0407baSopenharmony_ci	return sprintf(buffer, "unsupported to read\n");
4633d0407baSopenharmony_ci}
4643d0407baSopenharmony_ci
4653d0407baSopenharmony_cistatic ssize_t bluesleep_write_proc_lpm(struct file *file,
4663d0407baSopenharmony_ci					const char __user *buffer, size_t count,
4673d0407baSopenharmony_ci					loff_t *data)
4683d0407baSopenharmony_ci{
4693d0407baSopenharmony_ci	return count;
4703d0407baSopenharmony_ci}
4713d0407baSopenharmony_ci
4723d0407baSopenharmony_cistatic ssize_t bluesleep_read_proc_btwrite(struct file *file,
4733d0407baSopenharmony_ci					   char __user *buffer, size_t count,
4743d0407baSopenharmony_ci					   loff_t *data)
4753d0407baSopenharmony_ci{
4763d0407baSopenharmony_ci	return sprintf(buffer, "unsupported to read\n");
4773d0407baSopenharmony_ci}
4783d0407baSopenharmony_ci
4793d0407baSopenharmony_cistatic ssize_t bluesleep_write_proc_btwrite(struct file *file,
4803d0407baSopenharmony_ci					    const char __user *buffer,
4813d0407baSopenharmony_ci					    size_t count, loff_t *data)
4823d0407baSopenharmony_ci{
4833d0407baSopenharmony_ci	char b;
4843d0407baSopenharmony_ci
4853d0407baSopenharmony_ci	if (count < 1)
4863d0407baSopenharmony_ci		return -EINVAL;
4873d0407baSopenharmony_ci
4883d0407baSopenharmony_ci	if (copy_from_user(&b, buffer, 1))
4893d0407baSopenharmony_ci		return -EFAULT;
4903d0407baSopenharmony_ci
4913d0407baSopenharmony_ci	DBG("btwrite %c\n", b);
4923d0407baSopenharmony_ci	/* HCI_DEV_WRITE */
4933d0407baSopenharmony_ci	if (b != '0')
4943d0407baSopenharmony_ci		rfkill_rk_sleep_bt(BT_WAKEUP);
4953d0407baSopenharmony_ci	else
4963d0407baSopenharmony_ci		rfkill_rk_sleep_bt(BT_SLEEP);
4973d0407baSopenharmony_ci
4983d0407baSopenharmony_ci	return count;
4993d0407baSopenharmony_ci}
5003d0407baSopenharmony_ci
5013d0407baSopenharmony_ci#ifdef CONFIG_OF
5023d0407baSopenharmony_cistatic int bluetooth_platdata_parse_dt(struct device *dev,
5033d0407baSopenharmony_ci				       struct rfkill_rk_platform_data *data)
5043d0407baSopenharmony_ci{
5053d0407baSopenharmony_ci	struct device_node *node = dev->of_node;
5063d0407baSopenharmony_ci	int gpio;
5073d0407baSopenharmony_ci	enum of_gpio_flags flags;
5083d0407baSopenharmony_ci
5093d0407baSopenharmony_ci	if (!node)
5103d0407baSopenharmony_ci		return -ENODEV;
5113d0407baSopenharmony_ci
5123d0407baSopenharmony_ci	memset(data, 0, sizeof(*data));
5133d0407baSopenharmony_ci
5143d0407baSopenharmony_ci	if (of_find_property(node, "wifi-bt-power-toggle", NULL)) {
5153d0407baSopenharmony_ci		data->power_toggle = true;
5163d0407baSopenharmony_ci		LOG("%s: get property wifi-bt-power-toggle.\n", __func__);
5173d0407baSopenharmony_ci	} else {
5183d0407baSopenharmony_ci		data->power_toggle = false;
5193d0407baSopenharmony_ci	}
5203d0407baSopenharmony_ci
5213d0407baSopenharmony_ci	gpio = of_get_named_gpio_flags(node, "uart_rts_gpios", 0, &flags);
5223d0407baSopenharmony_ci	if (gpio_is_valid(gpio)) {
5233d0407baSopenharmony_ci		data->rts_gpio.io = gpio;
5243d0407baSopenharmony_ci		data->rts_gpio.enable = (flags == GPIO_ACTIVE_HIGH) ? 1 : 0;
5253d0407baSopenharmony_ci		LOG("%s: get property: uart_rts_gpios = %d.\n", __func__, gpio);
5263d0407baSopenharmony_ci		data->pinctrl = devm_pinctrl_get(dev);
5273d0407baSopenharmony_ci		if (!IS_ERR(data->pinctrl)) {
5283d0407baSopenharmony_ci			data->rts_gpio.default_state =
5293d0407baSopenharmony_ci				pinctrl_lookup_state(data->pinctrl, "default");
5303d0407baSopenharmony_ci			data->rts_gpio.gpio_state =
5313d0407baSopenharmony_ci				pinctrl_lookup_state(data->pinctrl, "rts_gpio");
5323d0407baSopenharmony_ci		} else {
5333d0407baSopenharmony_ci			data->pinctrl = NULL;
5343d0407baSopenharmony_ci			LOG("%s: dts does't define the uart rts iomux.\n",
5353d0407baSopenharmony_ci			    __func__);
5363d0407baSopenharmony_ci			return -EINVAL;
5373d0407baSopenharmony_ci		}
5383d0407baSopenharmony_ci	} else {
5393d0407baSopenharmony_ci		data->pinctrl = NULL;
5403d0407baSopenharmony_ci		data->rts_gpio.io = -EINVAL;
5413d0407baSopenharmony_ci		LOG("%s: uart_rts_gpios is no-in-use.\n", __func__);
5423d0407baSopenharmony_ci	}
5433d0407baSopenharmony_ci
5443d0407baSopenharmony_ci	gpio = of_get_named_gpio_flags(node, "BT,power_gpio", 0, &flags);
5453d0407baSopenharmony_ci	if (gpio_is_valid(gpio)) {
5463d0407baSopenharmony_ci		data->poweron_gpio.io = gpio;
5473d0407baSopenharmony_ci		data->poweron_gpio.enable = (flags == GPIO_ACTIVE_HIGH) ? 1 : 0;
5483d0407baSopenharmony_ci		LOG("%s: get property: BT,power_gpio = %d.\n", __func__, gpio);
5493d0407baSopenharmony_ci	} else {
5503d0407baSopenharmony_ci		data->poweron_gpio.io = -1;
5513d0407baSopenharmony_ci	}
5523d0407baSopenharmony_ci	gpio = of_get_named_gpio_flags(node, "BT,reset_gpio", 0, &flags);
5533d0407baSopenharmony_ci	if (gpio_is_valid(gpio)) {
5543d0407baSopenharmony_ci		data->reset_gpio.io = gpio;
5553d0407baSopenharmony_ci		data->reset_gpio.enable = (flags == GPIO_ACTIVE_HIGH) ? 1 : 0;
5563d0407baSopenharmony_ci		LOG("%s: get property: BT,reset_gpio = %d.\n", __func__, gpio);
5573d0407baSopenharmony_ci	} else {
5583d0407baSopenharmony_ci		data->reset_gpio.io = -1;
5593d0407baSopenharmony_ci	}
5603d0407baSopenharmony_ci	gpio = of_get_named_gpio_flags(node, "BT,wake_gpio", 0, &flags);
5613d0407baSopenharmony_ci	if (gpio_is_valid(gpio)) {
5623d0407baSopenharmony_ci		data->wake_gpio.io = gpio;
5633d0407baSopenharmony_ci		data->wake_gpio.enable = (flags == GPIO_ACTIVE_HIGH) ? 1 : 0;
5643d0407baSopenharmony_ci		LOG("%s: get property: BT,wake_gpio = %d.\n", __func__, gpio);
5653d0407baSopenharmony_ci	} else {
5663d0407baSopenharmony_ci		data->wake_gpio.io = -1;
5673d0407baSopenharmony_ci	}
5683d0407baSopenharmony_ci	gpio = of_get_named_gpio_flags(node, "BT,wake_host_irq", 0, &flags);
5693d0407baSopenharmony_ci	if (gpio_is_valid(gpio)) {
5703d0407baSopenharmony_ci		data->wake_host_irq.gpio.io = gpio;
5713d0407baSopenharmony_ci		data->wake_host_irq.gpio.enable = flags;
5723d0407baSopenharmony_ci		LOG("%s: get property: BT,wake_host_irq = %d.\n", __func__,
5733d0407baSopenharmony_ci		    gpio);
5743d0407baSopenharmony_ci	} else {
5753d0407baSopenharmony_ci		data->wake_host_irq.gpio.io = -1;
5763d0407baSopenharmony_ci	}
5773d0407baSopenharmony_ci
5783d0407baSopenharmony_ci	data->ext_clk = devm_clk_get(dev, "ext_clock");
5793d0407baSopenharmony_ci	if (IS_ERR(data->ext_clk)) {
5803d0407baSopenharmony_ci		LOG("%s: clk_get failed!!!.\n", __func__);
5813d0407baSopenharmony_ci	} else {
5823d0407baSopenharmony_ci		clk_prepare_enable(data->ext_clk);
5833d0407baSopenharmony_ci	}
5843d0407baSopenharmony_ci	return 0;
5853d0407baSopenharmony_ci}
5863d0407baSopenharmony_ci#endif //CONFIG_OF
5873d0407baSopenharmony_ci
5883d0407baSopenharmony_cistatic const struct proc_ops bluesleep_lpm = {
5893d0407baSopenharmony_ci	.proc_read = bluesleep_read_proc_lpm,
5903d0407baSopenharmony_ci	.proc_write = bluesleep_write_proc_lpm,
5913d0407baSopenharmony_ci};
5923d0407baSopenharmony_ci
5933d0407baSopenharmony_cistatic const struct proc_ops bluesleep_btwrite = {
5943d0407baSopenharmony_ci	.proc_read = bluesleep_read_proc_btwrite,
5953d0407baSopenharmony_ci	.proc_write = bluesleep_write_proc_btwrite,
5963d0407baSopenharmony_ci};
5973d0407baSopenharmony_ci
5983d0407baSopenharmony_cistatic int rfkill_rk_probe(struct platform_device *pdev)
5993d0407baSopenharmony_ci{
6003d0407baSopenharmony_ci	struct rfkill_rk_data *rfkill;
6013d0407baSopenharmony_ci	struct rfkill_rk_platform_data *pdata = pdev->dev.platform_data;
6023d0407baSopenharmony_ci	int ret = 0;
6033d0407baSopenharmony_ci	struct proc_dir_entry *ent;
6043d0407baSopenharmony_ci
6053d0407baSopenharmony_ci	DBG("Enter %s\n", __func__);
6063d0407baSopenharmony_ci
6073d0407baSopenharmony_ci	if (!pdata) {
6083d0407baSopenharmony_ci#ifdef CONFIG_OF
6093d0407baSopenharmony_ci		pdata = devm_kzalloc(&pdev->dev,
6103d0407baSopenharmony_ci				     sizeof(struct rfkill_rk_platform_data),
6113d0407baSopenharmony_ci				     GFP_KERNEL);
6123d0407baSopenharmony_ci		if (!pdata)
6133d0407baSopenharmony_ci			return -ENOMEM;
6143d0407baSopenharmony_ci
6153d0407baSopenharmony_ci		ret = bluetooth_platdata_parse_dt(&pdev->dev, pdata);
6163d0407baSopenharmony_ci		if (ret < 0) {
6173d0407baSopenharmony_ci#endif
6183d0407baSopenharmony_ci			LOG("%s: No platform data specified\n", __func__);
6193d0407baSopenharmony_ci			return ret;
6203d0407baSopenharmony_ci#ifdef CONFIG_OF
6213d0407baSopenharmony_ci		}
6223d0407baSopenharmony_ci#endif
6233d0407baSopenharmony_ci	}
6243d0407baSopenharmony_ci
6253d0407baSopenharmony_ci	pdata->name = (char *)bt_name;
6263d0407baSopenharmony_ci	pdata->type = RFKILL_TYPE_BLUETOOTH;
6273d0407baSopenharmony_ci
6283d0407baSopenharmony_ci	rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL);
6293d0407baSopenharmony_ci	if (!rfkill)
6303d0407baSopenharmony_ci		return -ENOMEM;
6313d0407baSopenharmony_ci
6323d0407baSopenharmony_ci	rfkill->pdata = pdata;
6333d0407baSopenharmony_ci	rfkill->pdev = pdev;
6343d0407baSopenharmony_ci	g_rfkill = rfkill;
6353d0407baSopenharmony_ci
6363d0407baSopenharmony_ci	bluetooth_dir = proc_mkdir("bluetooth", NULL);
6373d0407baSopenharmony_ci	if (!bluetooth_dir) {
6383d0407baSopenharmony_ci		LOG("Unable to create /proc/bluetooth directory");
6393d0407baSopenharmony_ci		return -ENOMEM;
6403d0407baSopenharmony_ci	}
6413d0407baSopenharmony_ci
6423d0407baSopenharmony_ci	sleep_dir = proc_mkdir("sleep", bluetooth_dir);
6433d0407baSopenharmony_ci	if (!sleep_dir) {
6443d0407baSopenharmony_ci		LOG("Unable to create /proc/%s directory", PROC_DIR);
6453d0407baSopenharmony_ci		return -ENOMEM;
6463d0407baSopenharmony_ci	}
6473d0407baSopenharmony_ci
6483d0407baSopenharmony_ci	/* read/write proc entries */
6493d0407baSopenharmony_ci	ent = proc_create("lpm", 0444, sleep_dir, &bluesleep_lpm);
6503d0407baSopenharmony_ci	if (!ent) {
6513d0407baSopenharmony_ci		LOG("Unable to create /proc/%s/lpm entry", PROC_DIR);
6523d0407baSopenharmony_ci		ret = -ENOMEM;
6533d0407baSopenharmony_ci		goto fail_alloc;
6543d0407baSopenharmony_ci	}
6553d0407baSopenharmony_ci
6563d0407baSopenharmony_ci	/* read/write proc entries */
6573d0407baSopenharmony_ci	ent = proc_create("btwrite", 0444, sleep_dir, &bluesleep_btwrite);
6583d0407baSopenharmony_ci	if (!ent) {
6593d0407baSopenharmony_ci		LOG("Unable to create /proc/%s/btwrite entry", PROC_DIR);
6603d0407baSopenharmony_ci		ret = -ENOMEM;
6613d0407baSopenharmony_ci		goto fail_alloc;
6623d0407baSopenharmony_ci	}
6633d0407baSopenharmony_ci
6643d0407baSopenharmony_ci	DBG("init gpio\n");
6653d0407baSopenharmony_ci
6663d0407baSopenharmony_ci	ret = rfkill_rk_setup_gpio(pdev, &pdata->poweron_gpio, pdata->name,
6673d0407baSopenharmony_ci				   "poweron");
6683d0407baSopenharmony_ci	if (ret)
6693d0407baSopenharmony_ci		goto fail_gpio;
6703d0407baSopenharmony_ci
6713d0407baSopenharmony_ci	ret = rfkill_rk_setup_gpio(pdev, &pdata->reset_gpio, pdata->name,
6723d0407baSopenharmony_ci				   "reset");
6733d0407baSopenharmony_ci	if (ret)
6743d0407baSopenharmony_ci		goto fail_gpio;
6753d0407baSopenharmony_ci
6763d0407baSopenharmony_ci	ret = rfkill_rk_setup_gpio(pdev, &pdata->wake_gpio, pdata->name,
6773d0407baSopenharmony_ci				   "wake");
6783d0407baSopenharmony_ci	if (ret)
6793d0407baSopenharmony_ci		goto fail_gpio;
6803d0407baSopenharmony_ci
6813d0407baSopenharmony_ci	ret = rfkill_rk_setup_gpio(pdev, &pdata->rts_gpio, rfkill->pdata->name,
6823d0407baSopenharmony_ci				   "rts");
6833d0407baSopenharmony_ci	if (ret)
6843d0407baSopenharmony_ci		goto fail_gpio;
6853d0407baSopenharmony_ci
6863d0407baSopenharmony_ci	wake_lock_init(&rfkill->bt_irq_wl, WAKE_LOCK_SUSPEND,
6873d0407baSopenharmony_ci		       "rfkill_rk_irq_wl");
6883d0407baSopenharmony_ci
6893d0407baSopenharmony_ci	ret = rfkill_rk_setup_wake_irq(rfkill, 0);
6903d0407baSopenharmony_ci	if (ret)
6913d0407baSopenharmony_ci		goto fail_setup_wake_irq;
6923d0407baSopenharmony_ci
6933d0407baSopenharmony_ci	DBG("setup rfkill\n");
6943d0407baSopenharmony_ci	rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type,
6953d0407baSopenharmony_ci					  &rfkill_rk_ops, rfkill);
6963d0407baSopenharmony_ci	if (!rfkill->rfkill_dev)
6973d0407baSopenharmony_ci		goto fail_alloc;
6983d0407baSopenharmony_ci
6993d0407baSopenharmony_ci	rfkill_init_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
7003d0407baSopenharmony_ci	rfkill_set_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
7013d0407baSopenharmony_ci	rfkill_set_hw_state(rfkill->rfkill_dev, false);
7023d0407baSopenharmony_ci	ret = rfkill_register(rfkill->rfkill_dev);
7033d0407baSopenharmony_ci	if (ret < 0)
7043d0407baSopenharmony_ci		goto fail_rfkill;
7053d0407baSopenharmony_ci
7063d0407baSopenharmony_ci	INIT_DELAYED_WORK(&rfkill->bt_sleep_delay_work,
7073d0407baSopenharmony_ci			  rfkill_rk_delay_sleep_bt);
7083d0407baSopenharmony_ci
7093d0407baSopenharmony_ci	//rfkill_rk_set_power(rfkill, BT_BLOCKED);
7103d0407baSopenharmony_ci	// bt turn off power
7113d0407baSopenharmony_ci	if (gpio_is_valid(pdata->poweron_gpio.io)) {
7123d0407baSopenharmony_ci		gpio_direction_output(pdata->poweron_gpio.io,
7133d0407baSopenharmony_ci				      !pdata->poweron_gpio.enable);
7143d0407baSopenharmony_ci	}
7153d0407baSopenharmony_ci	if (gpio_is_valid(pdata->reset_gpio.io)) {
7163d0407baSopenharmony_ci		gpio_direction_output(pdata->reset_gpio.io,
7173d0407baSopenharmony_ci				      !pdata->reset_gpio.enable);
7183d0407baSopenharmony_ci	}
7193d0407baSopenharmony_ci
7203d0407baSopenharmony_ci	platform_set_drvdata(pdev, rfkill);
7213d0407baSopenharmony_ci
7223d0407baSopenharmony_ci	LOG("%s device registered.\n", pdata->name);
7233d0407baSopenharmony_ci
7243d0407baSopenharmony_ci	return 0;
7253d0407baSopenharmony_ci
7263d0407baSopenharmony_cifail_rfkill:
7273d0407baSopenharmony_ci	rfkill_destroy(rfkill->rfkill_dev);
7283d0407baSopenharmony_cifail_alloc:
7293d0407baSopenharmony_ci
7303d0407baSopenharmony_ci	remove_proc_entry("btwrite", sleep_dir);
7313d0407baSopenharmony_ci	remove_proc_entry("lpm", sleep_dir);
7323d0407baSopenharmony_cifail_setup_wake_irq:
7333d0407baSopenharmony_ci	wake_lock_destroy(&rfkill->bt_irq_wl);
7343d0407baSopenharmony_cifail_gpio:
7353d0407baSopenharmony_ci
7363d0407baSopenharmony_ci	g_rfkill = NULL;
7373d0407baSopenharmony_ci	return ret;
7383d0407baSopenharmony_ci}
7393d0407baSopenharmony_ci
7403d0407baSopenharmony_cistatic int rfkill_rk_remove(struct platform_device *pdev)
7413d0407baSopenharmony_ci{
7423d0407baSopenharmony_ci	struct rfkill_rk_data *rfkill = platform_get_drvdata(pdev);
7433d0407baSopenharmony_ci
7443d0407baSopenharmony_ci	LOG("Enter %s\n", __func__);
7453d0407baSopenharmony_ci
7463d0407baSopenharmony_ci	rfkill_unregister(rfkill->rfkill_dev);
7473d0407baSopenharmony_ci	rfkill_destroy(rfkill->rfkill_dev);
7483d0407baSopenharmony_ci
7493d0407baSopenharmony_ci	cancel_delayed_work_sync(&rfkill->bt_sleep_delay_work);
7503d0407baSopenharmony_ci
7513d0407baSopenharmony_ci	// free gpio
7523d0407baSopenharmony_ci	if (gpio_is_valid(rfkill->pdata->rts_gpio.io))
7533d0407baSopenharmony_ci		gpio_free(rfkill->pdata->rts_gpio.io);
7543d0407baSopenharmony_ci
7553d0407baSopenharmony_ci	if (gpio_is_valid(rfkill->pdata->wake_host_irq.gpio.io)) {
7563d0407baSopenharmony_ci		free_irq(rfkill->pdata->wake_host_irq.irq, rfkill);
7573d0407baSopenharmony_ci#ifndef CONFIG_BK3515A_COMBO
7583d0407baSopenharmony_ci		gpio_free(rfkill->pdata->wake_host_irq.gpio.io);
7593d0407baSopenharmony_ci#endif
7603d0407baSopenharmony_ci	}
7613d0407baSopenharmony_ci
7623d0407baSopenharmony_ci#ifndef CONFIG_BK3515A_COMBO
7633d0407baSopenharmony_ci	if (gpio_is_valid(rfkill->pdata->wake_gpio.io))
7643d0407baSopenharmony_ci		gpio_free(rfkill->pdata->wake_gpio.io);
7653d0407baSopenharmony_ci#endif
7663d0407baSopenharmony_ci
7673d0407baSopenharmony_ci	if (gpio_is_valid(rfkill->pdata->reset_gpio.io))
7683d0407baSopenharmony_ci		gpio_free(rfkill->pdata->reset_gpio.io);
7693d0407baSopenharmony_ci
7703d0407baSopenharmony_ci	if (gpio_is_valid(rfkill->pdata->poweron_gpio.io))
7713d0407baSopenharmony_ci		gpio_free(rfkill->pdata->poweron_gpio.io);
7723d0407baSopenharmony_ci	clk_disable_unprepare(rfkill->pdata->ext_clk);
7733d0407baSopenharmony_ci	wake_lock_destroy(&rfkill->bt_irq_wl);
7743d0407baSopenharmony_ci	g_rfkill = NULL;
7753d0407baSopenharmony_ci
7763d0407baSopenharmony_ci	return 0;
7773d0407baSopenharmony_ci}
7783d0407baSopenharmony_ci
7793d0407baSopenharmony_cistatic const struct dev_pm_ops rfkill_rk_pm_ops = {
7803d0407baSopenharmony_ci	.prepare = rfkill_rk_pm_prepare,
7813d0407baSopenharmony_ci	.complete = rfkill_rk_pm_complete,
7823d0407baSopenharmony_ci};
7833d0407baSopenharmony_ci
7843d0407baSopenharmony_ci#ifdef CONFIG_OF
7853d0407baSopenharmony_cistatic struct of_device_id bt_platdata_of_match[] = {
7863d0407baSopenharmony_ci	{ .compatible = "bluetooth-platdata" },
7873d0407baSopenharmony_ci	{}
7883d0407baSopenharmony_ci};
7893d0407baSopenharmony_ciMODULE_DEVICE_TABLE(of, bt_platdata_of_match);
7903d0407baSopenharmony_ci#endif //CONFIG_OF
7913d0407baSopenharmony_ci
7923d0407baSopenharmony_cistatic struct platform_driver rfkill_rk_driver = {
7933d0407baSopenharmony_ci	.probe = rfkill_rk_probe,
7943d0407baSopenharmony_ci	.remove = rfkill_rk_remove,
7953d0407baSopenharmony_ci	.driver = {
7963d0407baSopenharmony_ci		.name = "rfkill_bt",
7973d0407baSopenharmony_ci		.owner = THIS_MODULE,
7983d0407baSopenharmony_ci		.pm = &rfkill_rk_pm_ops,
7993d0407baSopenharmony_ci        .of_match_table = of_match_ptr(bt_platdata_of_match),
8003d0407baSopenharmony_ci	},
8013d0407baSopenharmony_ci};
8023d0407baSopenharmony_ci
8033d0407baSopenharmony_cistatic int __init rfkill_rk_init(void)
8043d0407baSopenharmony_ci{
8053d0407baSopenharmony_ci	int err;
8063d0407baSopenharmony_ci
8073d0407baSopenharmony_ci	LOG("Enter %s\n", __func__);
8083d0407baSopenharmony_ci	err = rfkill_wlan_init();
8093d0407baSopenharmony_ci	if (err)
8103d0407baSopenharmony_ci		return err;
8113d0407baSopenharmony_ci	return platform_driver_register(&rfkill_rk_driver);
8123d0407baSopenharmony_ci}
8133d0407baSopenharmony_ci
8143d0407baSopenharmony_cistatic void __exit rfkill_rk_exit(void)
8153d0407baSopenharmony_ci{
8163d0407baSopenharmony_ci	LOG("Enter %s\n", __func__);
8173d0407baSopenharmony_ci	platform_driver_unregister(&rfkill_rk_driver);
8183d0407baSopenharmony_ci	rfkill_wlan_exit();
8193d0407baSopenharmony_ci}
8203d0407baSopenharmony_ci
8213d0407baSopenharmony_cimodule_init(rfkill_rk_init);
8223d0407baSopenharmony_cimodule_exit(rfkill_rk_exit);
8233d0407baSopenharmony_ci
8243d0407baSopenharmony_ciMODULE_DESCRIPTION("rock-chips rfkill for Bluetooth v0.3");
8253d0407baSopenharmony_ciMODULE_AUTHOR("cmy@rock-chips.com, gwl@rock-chips.com");
8263d0407baSopenharmony_ciMODULE_LICENSE("GPL");
827