BT: add a gpio interrupt for bt [1/1]
authorKuibao Zhang <kuibao.zhang@amlogic.com>
Wed, 1 May 2019 15:06:47 +0000 (23:06 +0800)
committerTao Zeng <tao.zeng@amlogic.com>
Wed, 8 May 2019 08:41:15 +0000 (01:41 -0700)
PD#TV-5021

Problem:
    1.bt rcu cann't wakeup host when the system is in freeze mode;
    2.There is no wake source in the bluetooth kernel.
    3.current irqchip driver will complain "Unbalanced IRQ xx wake
    disable" when gpio irq use as wakeup source, and can not wake device.

Solution:
    1.add a gpio interrupt for bt in the bt kernel;
    2.Wake up the interrupt;
    3.Add a flag to skip undefined  .irq_set_wake function in irqchip
    driver.

Verify:
    marconi.

Change-Id: Ic8d5525621e015a13fd765779f944cd1010144aa
Signed-off-by: Kuibao Zhang <kuibao.zhang@amlogic.com>
drivers/amlogic/bluetooth/bt_device.c
drivers/amlogic/irqchip/irq-meson-gpio.c
include/linux/amlogic/bt_device.h

index 3d7afc4..5785e02 100644 (file)
 #endif
 #include "../../gpio/gpiolib.h"
 
+#include <linux/interrupt.h>
+#include <linux/pm_wakeup.h>
+#include <linux/pm_wakeirq.h>
+
 #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND
 #include <linux/amlogic/pm.h>
 static struct early_suspend bt_early_suspend;
@@ -199,6 +203,12 @@ static void bt_device_on(struct bt_dev_data *pdata)
        msleep(200);
 }
 
+/*The system calls this function when GPIOC_14 interrupt occurs*/
+static irqreturn_t bt_interrupt(int irq, void *dev_id)
+{
+       pr_info("freeze: test BT IRQ\n");
+       return IRQ_HANDLED;
+}
 static int bt_set_block(void *data, bool blocked)
 {
        struct bt_dev_data *pdata = data;
@@ -232,12 +242,20 @@ static void bt_lateresume(struct early_suspend *h)
 static int bt_suspend(struct platform_device *pdev,
        pm_message_t state)
 {
+       struct bt_dev_data *pdata = platform_get_drvdata(pdev);
+
+       pr_info("bt suspend\n");
+       enable_irq(pdata->irqno_wakeup);
 
        return 0;
 }
 
 static int bt_resume(struct platform_device *pdev)
 {
+       struct bt_dev_data *pdata = platform_get_drvdata(pdev);
+
+       pr_info("bt resume\n");
+       disable_irq(pdata->irqno_wakeup);
 
        return 0;
 }
@@ -288,6 +306,17 @@ static int bt_probe(struct platform_device *pdev)
                                "gpio_hostwake", 0, NULL);
                        pdata->gpio_hostwake = desc_to_gpio(desc);
                }
+               /*gpio_btwakeup = BT_WAKE_HOST*/
+               ret = of_property_read_string(pdev->dev.of_node,
+                       "gpio_btwakeup", &str);
+               if (ret) {
+                       pr_warn("not get gpio_btwakeup\n");
+                       pdata->gpio_btwakeup = 0;
+               } else {
+                       desc = of_get_named_gpiod_flags(pdev->dev.of_node,
+                               "gpio_btwakeup", 0, NULL);
+                       pdata->gpio_btwakeup = desc_to_gpio(desc);
+               }
 
                prop = of_get_property(pdev->dev.of_node,
                "power_low_level", NULL);
@@ -372,6 +401,28 @@ static int bt_probe(struct platform_device *pdev)
        register_early_suspend(&bt_early_suspend);
 #endif
 
+       platform_set_drvdata(pdev, pdata);
+
+       /*1.Set BT_WAKE_HOST to the input state;*/
+       /*2.Get interrupt number(irqno_wakeup).*/
+       pdata->irqno_wakeup = gpio_to_irq(pdata->gpio_btwakeup);
+
+       /*Register interrupt service function*/
+       ret = request_irq(pdata->irqno_wakeup, bt_interrupt,
+                       IRQF_TRIGGER_FALLING, "bt-irq", (void *)pdata);
+       if (ret < 0)
+               pr_err("request_irq error ret=%d\n", ret);
+
+       disable_irq(pdata->irqno_wakeup);
+
+       ret = device_init_wakeup(&pdev->dev, 1);
+       if (ret)
+               pr_err("device_init_wakeup failed: %d\n", ret);
+       /*Wake up the interrupt*/
+       ret = dev_pm_set_wake_irq(&pdev->dev, pdata->irqno_wakeup);
+       if (ret)
+               pr_err("dev_pm_set_wake_irq failed: %d\n", ret);
+
        return 0;
 
 err_rfkill:
index b1d1504..507f81c 100644 (file)
@@ -292,7 +292,7 @@ static struct irq_chip meson_gpio_irq_chip = {
 #ifdef CONFIG_SMP
        .irq_set_affinity       = irq_chip_set_affinity_parent,
 #endif
-       .flags                  = IRQCHIP_SET_TYPE_MASKED,
+       .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE,
 };
 
 static int meson_gpio_irq_domain_translate(struct irq_domain *domain,
index 6865f00..d7d69a6 100644 (file)
@@ -22,10 +22,12 @@ struct bt_dev_data {
        int gpio_reset;
        int gpio_en;
        int gpio_hostwake;
+       int gpio_btwakeup;
        int power_low_level;
        int power_on_pin_OD;
        int power_off_flag;
        int power_down_disable;
+       int irqno_wakeup;
 };
 extern void set_usb_bt_power(int is_power);
 #endif