net: rfkill-bt: add power up func when waked by bt-irq only.
when rtk(also some others) wifi/bt combo chips suspend, it disconnect from bt-remote control unit(RCU). when RCU's powerkey pressed, it will send ble broadcast to rtk bt chip. As the rtk chips receive the broadcast, it should wake up the host, but it can't send bt-hid powerkey to host because it had lost communication with host. So,it just send a IRQ pulse to host. The host should resume from suspend. Because the RCU just send a IRQ pulse, so rk chips just resume by IRQ and then go to sleep again for no power-key event. this is not expected. we expect to power up system wholly. With this path, we try to power up the system. so we add a power-up key event when BT IRQ received. We also can control the "/proc/bluetooth/sleep/powerupkey" node to enable or disable this function. Change-Id: Ie59b4a2c4cd2f91820d31835df86565003126465 Signed-off-by: Zou Dengming <marsow.zou@rock-chips.com>
This commit is contained in:
parent
f98648322e
commit
19ab80fe27
2 changed files with 127 additions and 11 deletions
|
|
@ -35,6 +35,7 @@ config RFKILL_GPIO
|
|||
|
||||
config RFKILL_RK
|
||||
tristate "Rockchip RFKILL driver"
|
||||
select INPUT
|
||||
depends on RFKILL
|
||||
depends on MMC
|
||||
depends on ARCH_ROCKCHIP
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/rfkill-bt.h>
|
||||
#include <linux/rfkill-wlan.h>
|
||||
#include <linux/wakelock.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/irq.h>
|
||||
#include <linux/suspend.h>
|
||||
|
|
@ -69,9 +70,11 @@ struct rfkill_rk_data {
|
|||
struct wake_lock bt_irq_wl;
|
||||
struct delayed_work bt_sleep_delay_work;
|
||||
int irq_req;
|
||||
bool enable_power_key;
|
||||
};
|
||||
|
||||
static struct rfkill_rk_data *g_rfkill = NULL;
|
||||
static struct input_dev *power_key_dev;
|
||||
|
||||
static const char bt_name[] =
|
||||
#if defined(CONFIG_BCM4330)
|
||||
|
|
@ -113,6 +116,20 @@ static const char bt_name[] =
|
|||
#endif
|
||||
;
|
||||
|
||||
static int rfkill_rk_power_key_up(void)
|
||||
{
|
||||
if (!power_key_dev)
|
||||
return -ENODEV;
|
||||
|
||||
input_report_key(power_key_dev, KEY_POWER, 1);
|
||||
input_sync(power_key_dev);
|
||||
msleep(20);
|
||||
input_report_key(power_key_dev, KEY_POWER, 0);
|
||||
input_sync(power_key_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t rfkill_rk_wake_host_irq(int irq, void *dev)
|
||||
{
|
||||
struct rfkill_rk_data *rfkill = dev;
|
||||
|
|
@ -124,6 +141,16 @@ static irqreturn_t rfkill_rk_wake_host_irq(int irq, void *dev)
|
|||
wake_lock_timeout(&rfkill->bt_irq_wl,
|
||||
msecs_to_jiffies(BT_IRQ_WAKELOCK_TIMEOUT));
|
||||
|
||||
if (rfkill->enable_power_key)
|
||||
return IRQ_WAKE_THREAD;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rfkill_rk_wake_host_irq_thread(int irq, void *dev)
|
||||
{
|
||||
rfkill_rk_power_key_up();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
@ -165,11 +192,12 @@ static int rfkill_rk_setup_wake_irq(struct rfkill_rk_data *rfkill, int flag)
|
|||
LOG("Request irq for bt wakeup host\n");
|
||||
irq->irq = gpio_to_irq(irq->gpio.io);
|
||||
sprintf(irq->name, "%s_irq", irq->gpio.name);
|
||||
ret = request_irq(irq->irq, rfkill_rk_wake_host_irq,
|
||||
(irq->gpio.enable == GPIO_ACTIVE_LOW) ?
|
||||
IRQF_TRIGGER_FALLING :
|
||||
IRQF_TRIGGER_RISING,
|
||||
irq->name, rfkill);
|
||||
ret = request_threaded_irq(irq->irq, rfkill_rk_wake_host_irq,
|
||||
rfkill_rk_wake_host_irq_thread,
|
||||
IRQF_ONESHOT | ((irq->gpio.enable == GPIO_ACTIVE_LOW) ?
|
||||
IRQF_TRIGGER_FALLING :
|
||||
IRQF_TRIGGER_RISING),
|
||||
irq->name, rfkill);
|
||||
if (ret)
|
||||
goto fail2;
|
||||
rfkill->irq_req = 1;
|
||||
|
|
@ -488,7 +516,6 @@ static ssize_t bluesleep_write_proc_btwrite(struct file *file,
|
|||
return -EFAULT;
|
||||
|
||||
DBG("btwrite %c\n", b);
|
||||
/* HCI_DEV_WRITE */
|
||||
if (b != '0')
|
||||
rfkill_rk_sleep_bt(BT_WAKEUP);
|
||||
else
|
||||
|
|
@ -497,6 +524,52 @@ static ssize_t bluesleep_write_proc_btwrite(struct file *file,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t bluesleep_read_proc_powerupkey(struct file *file,
|
||||
char __user *buffer, size_t count,
|
||||
loff_t *data)
|
||||
{
|
||||
struct rfkill_rk_data *rfkill = g_rfkill;
|
||||
char src[2];
|
||||
|
||||
if (*data >= 1)
|
||||
return 0;
|
||||
|
||||
if (!rfkill)
|
||||
return -EFAULT;
|
||||
|
||||
src[0] = rfkill->enable_power_key ? '1' : '0';
|
||||
src[1] = '\n';
|
||||
if (copy_to_user(buffer, src, 2))
|
||||
return -EFAULT;
|
||||
*data = 1;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static ssize_t bluesleep_write_proc_powerupkey(struct file *file,
|
||||
const char __user *buffer,
|
||||
size_t count, loff_t *data)
|
||||
{
|
||||
char b;
|
||||
struct rfkill_rk_data *rfkill = g_rfkill;
|
||||
|
||||
if (!rfkill)
|
||||
return -EFAULT;
|
||||
|
||||
if (count < 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&b, buffer, 1))
|
||||
return -EFAULT;
|
||||
|
||||
if (b != '0')
|
||||
rfkill->enable_power_key = true;
|
||||
else
|
||||
rfkill->enable_power_key = false;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int bluetooth_platdata_parse_dt(struct device *dev,
|
||||
struct rfkill_rk_platform_data *data)
|
||||
|
|
@ -594,6 +667,37 @@ static const struct proc_ops bluesleep_btwrite = {
|
|||
.proc_write = bluesleep_write_proc_btwrite,
|
||||
};
|
||||
|
||||
static const struct proc_ops bluesleep_powerupkey = {
|
||||
.proc_read = bluesleep_read_proc_powerupkey,
|
||||
.proc_write = bluesleep_write_proc_powerupkey,
|
||||
};
|
||||
|
||||
static int rfkill_rk_register_power_key(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* register input device */
|
||||
power_key_dev = devm_input_allocate_device(dev);
|
||||
if (!power_key_dev) {
|
||||
LOG("%s: not enough memory for input device\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
power_key_dev->name = "bt-powerkey";
|
||||
power_key_dev->id.bustype = BUS_HOST;
|
||||
|
||||
power_key_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
set_bit(KEY_POWER, power_key_dev->keybit);
|
||||
|
||||
ret = input_register_device(power_key_dev);
|
||||
if (ret) {
|
||||
LOG("%s: register input device exception, exit\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rfkill_rk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rfkill_rk_data *rfkill;
|
||||
|
|
@ -660,6 +764,14 @@ static int rfkill_rk_probe(struct platform_device *pdev)
|
|||
goto fail_alloc;
|
||||
}
|
||||
|
||||
/* read/write proc entries */
|
||||
ent = proc_create("powerupkey", 0444, sleep_dir, &bluesleep_powerupkey);
|
||||
if (!ent) {
|
||||
LOG("Unable to create /proc/%s/powerupkey entry", PROC_DIR);
|
||||
ret = -ENOMEM;
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
DBG("init gpio\n");
|
||||
|
||||
ret = rfkill_rk_setup_gpio(pdev, &pdata->poweron_gpio, pdata->name,
|
||||
|
|
@ -692,8 +804,10 @@ static int rfkill_rk_probe(struct platform_device *pdev)
|
|||
DBG("setup rfkill\n");
|
||||
rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type,
|
||||
&rfkill_rk_ops, rfkill);
|
||||
if (!rfkill->rfkill_dev)
|
||||
if (!rfkill->rfkill_dev) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
rfkill_init_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
|
||||
rfkill_set_sw_state(rfkill->rfkill_dev, BT_BLOCKED);
|
||||
|
|
@ -720,18 +834,18 @@ static int rfkill_rk_probe(struct platform_device *pdev)
|
|||
|
||||
LOG("%s device registered.\n", pdata->name);
|
||||
|
||||
if (rfkill_rk_register_power_key(&pdev->dev) != 0)
|
||||
goto fail_rfkill;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_rfkill:
|
||||
rfkill_destroy(rfkill->rfkill_dev);
|
||||
fail_alloc:
|
||||
|
||||
remove_proc_entry("btwrite", sleep_dir);
|
||||
remove_proc_entry("lpm", sleep_dir);
|
||||
remove_proc_subtree("bluetooth/sleep", NULL);
|
||||
fail_setup_wake_irq:
|
||||
wake_lock_destroy(&rfkill->bt_irq_wl);
|
||||
fail_gpio:
|
||||
|
||||
g_rfkill = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -744,6 +858,7 @@ static int rfkill_rk_remove(struct platform_device *pdev)
|
|||
|
||||
rfkill_unregister(rfkill->rfkill_dev);
|
||||
rfkill_destroy(rfkill->rfkill_dev);
|
||||
remove_proc_subtree("bluetooth/sleep", NULL);
|
||||
|
||||
cancel_delayed_work_sync(&rfkill->bt_sleep_delay_work);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue