#include <linux/rfkill.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <asm/gpio.h>
#include <linux/delay.h>
#include <linux/rfkill-bt.h>
+#include <linux/rfkill-wlan.h>
#include <linux/wakelock.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
+#include <linux/fs.h>
#include <dt-bindings/gpio/gpio.h>
#include <uapi/linux/rfkill.h>
#ifdef CONFIG_OF
}
EXPORT_SYMBOL(rfkill_rk_sleep_bt);
+static int bt_power_state = 0;
+int rfkill_get_bt_power_state(int *power, bool *toggle)
+{
+ struct rfkill_rk_data *mrfkill = g_rfkill;
+
+ if (mrfkill == NULL) {
+ LOG("%s: rfkill-bt driver has not Successful initialized\n", __func__);
+ return -1;
+ }
+
+ *toggle = mrfkill->pdata->power_toggle;
+ *power = bt_power_state;
+
+ return 0;
+}
+
static int rfkill_rk_set_power(void *data, bool blocked)
{
struct rfkill_rk_data *rfkill = data;
struct rfkill_rk_gpio *poweron = &rfkill->pdata->poweron_gpio;
struct rfkill_rk_gpio *reset = &rfkill->pdata->reset_gpio;
-#if defined(CONFIG_AP6210) || defined(CONFIG_AP6335)
struct rfkill_rk_gpio* rts = &rfkill->pdata->rts_gpio;
struct pinctrl *pinctrl = rfkill->pdata->pinctrl;
-#endif
+ int power = 0, vref_ctrl_enable = 0;
+ bool toggle = false;
DBG("Enter %s\n", __func__);
DBG("Set blocked:%d\n", blocked);
+ toggle = rfkill->pdata->power_toggle;
+ if (!rfkill_get_wifi_power_state(&power, &vref_ctrl_enable)) {
+ if (true == toggle && 1 == power) {
+ LOG("%s: bt shouldn't control the power, it was enabled by wifi!\n", __func__);
+ return 0;
+ }
+ } else {
+ LOG("%s: cannot get wifi power state!\n", __func__);
+ return -1;
+ }
+
if (false == blocked) {
+
rfkill_rk_sleep_bt(BT_WAKEUP); // ensure bt is wakeup
if (gpio_is_valid(poweron->io))
msleep(20);
gpio_direction_output(reset->io, reset->enable);
}
-#if defined(CONFIG_AP6210) || defined(CONFIG_AP6335)
+
if (pinctrl != NULL && gpio_is_valid(rts->io))
{
pinctrl_select_state(pinctrl, rts->gpio_state);
gpio_direction_output(rts->io, !rts->enable);
pinctrl_select_state(pinctrl, rts->default_state);
}
-#endif
+
+ bt_power_state = 1;
LOG("bt turn on power\n");
} else {
if (gpio_is_valid(poweron->io))
msleep(20);
}
+ bt_power_state = 0;
LOG("bt shut off power\n");
if (gpio_is_valid(reset->io))
{
gpio_direction_output(reset->io, !reset->enable);/* bt reset active*/
msleep(20);
}
+
}
return 0;
static struct proc_dir_entry *bluetooth_dir, *sleep_dir;
-static int bluesleep_read_proc_lpm(char *page, char **start, off_t offset,
- int count, int *eof, void *data)
+static ssize_t bluesleep_read_proc_lpm(struct file *file, char __user *buffer,
+ size_t count, loff_t *data)
{
- *eof = 1;
- return sprintf(page, "unsupported to read\n");
+ return sprintf(buffer, "unsupported to read\n");
}
-static int bluesleep_write_proc_lpm(struct file *file, const char *buffer,
- unsigned long count, void *data)
+static ssize_t bluesleep_write_proc_lpm(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *data)
{
return count;
}
-static int bluesleep_read_proc_btwrite(char *page, char **start, off_t offset,
- int count, int *eof, void *data)
+static ssize_t bluesleep_read_proc_btwrite(struct file *file,
+ char __user *buffer,
+ size_t count, loff_t *data)
{
- *eof = 1;
- return sprintf(page, "unsupported to read\n");
+ return sprintf(buffer, "unsupported to read\n");
}
-static int bluesleep_write_proc_btwrite(struct file *file, const char *buffer,
- unsigned long count, void *data)
+static ssize_t bluesleep_write_proc_btwrite(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *data)
{
char b;
memset(data, 0, sizeof(*data));
+ if (of_find_property(node, "wifi-bt-power-toggle", NULL)) {
+ data->power_toggle = true;
+ LOG("%s: get property wifi-bt-power-toggle.\n", __func__);
+ } else {
+ data->power_toggle = false;
+ }
+
gpio = of_get_named_gpio_flags(node, "uart_rts_gpios", 0, &flags);
if (gpio_is_valid(gpio)) {
data->rts_gpio.io = gpio;
data->poweron_gpio.io = gpio;
data->poweron_gpio.enable = (flags == GPIO_ACTIVE_HIGH)? 1:0;
LOG("%s: get property: BT,power_gpio = %d.\n", __func__, gpio);
- }
+ } else data->poweron_gpio.io = -1;
gpio = of_get_named_gpio_flags(node, "BT,reset_gpio", 0, &flags);
if (gpio_is_valid(gpio)){
data->reset_gpio.io = gpio;
data->reset_gpio.enable = (flags == GPIO_ACTIVE_HIGH)? 1:0;
LOG("%s: get property: BT,reset_gpio = %d.\n", __func__, gpio);
- }
+ } else data->reset_gpio.io = -1;
gpio = of_get_named_gpio_flags(node, "BT,wake_gpio", 0, &flags);
if (gpio_is_valid(gpio)){
data->wake_gpio.io = gpio;
data->wake_gpio.enable = (flags == GPIO_ACTIVE_HIGH)? 1:0;
LOG("%s: get property: BT,wake_gpio = %d.\n", __func__, gpio);
- }
+ } else data->wake_gpio.io = -1;
gpio = of_get_named_gpio_flags(node, "BT,wake_host_irq", 0, &flags);
if (gpio_is_valid(gpio)) {
data->wake_host_irq.gpio.io = gpio;
data->wake_host_irq.gpio.enable = flags;
LOG("%s: get property: BT,wake_host_irq = %d.\n", __func__, gpio);
- }
+ } else data->wake_host_irq.gpio.io = -1;
- return 0;
+ data->ext_clk = devm_clk_get(dev, "ext_clock");
+ if (IS_ERR(data->ext_clk)) {
+ LOG("%s: clk_get failed!!!.\n", __func__);
+ } else {
+ clk_prepare_enable(data->ext_clk);
+ }
+ return 0;
}
#endif //CONFIG_OF
pdata->type = RFKILL_TYPE_BLUETOOTH;
rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL);
- if (!rfkill) {
- kfree(pdata);
+ if (!rfkill)
return -ENOMEM;
- }
rfkill->pdata = pdata;
rfkill->pdev = pdev;
ret = rfkill_rk_setup_gpio(pdev, &pdata->wake_gpio, pdata->name, "wake");
if (ret) goto fail_gpio;
- ret = rfkill_rk_setup_wake_irq(rfkill);
+ ret = rfkill_rk_setup_gpio(pdev, &pdata->rts_gpio, rfkill->pdata->name, "rts");
if (ret) goto fail_gpio;
- ret = rfkill_rk_setup_gpio(pdev, &pdata->rts_gpio, rfkill->pdata->name, "rts");
+ wake_lock_init(&(rfkill->bt_irq_wl), WAKE_LOCK_SUSPEND, "rfkill_rk_irq_wl");
+
+ ret = rfkill_rk_setup_wake_irq(rfkill);
if (ret) goto fail_gpio;
DBG("setup rfkill\n");
if (ret < 0)
goto fail_rfkill;
- wake_lock_init(&(rfkill->bt_irq_wl), WAKE_LOCK_SUSPEND, "rfkill_rk_irq_wl");
INIT_DELAYED_WORK(&rfkill->bt_sleep_delay_work, rfkill_rk_delay_sleep_bt);
//rfkill_rk_set_power(rfkill, BT_BLOCKED);
fail_rfkill:
rfkill_destroy(rfkill->rfkill_dev);
fail_alloc:
- g_rfkill = NULL;
remove_proc_entry("btwrite", sleep_dir);
remove_proc_entry("lpm", sleep_dir);
fail_gpio:
+ g_rfkill = NULL;
return ret;
}
if (gpio_is_valid(rfkill->pdata->poweron_gpio.io))
gpio_free(rfkill->pdata->poweron_gpio.io);
-
- kfree(rfkill);
+ clk_disable_unprepare(rfkill->pdata->ext_clk);
g_rfkill = NULL;
return 0;