diff options
author | Balakrishna Godavarthi <quic_bgodavar@quicinc.com> | 2021-12-30 14:48:51 +0530 |
---|---|---|
committer | Cheney Ni <cheneyni@google.com> | 2022-04-19 09:59:55 +0000 |
commit | 217ce5e0d7c2658509dd43b42a6def4882f5c917 (patch) | |
tree | ce194d889d1b52274ca0f4a6f2c0dbc2a1ff6f1d | |
parent | 50a13cc73c3ed7a52988bee97e39fcfb0dc689ce (diff) | |
download | qcom-217ce5e0d7c2658509dd43b42a6def4882f5c917.tar.gz |
Add out of band sleep support to bluetooth driver
This change adds out of band sleep support to bluetooth
power driver. This feature will be enabled when macro
CONFIG_MSM_BT_OOBS is define.
Change-Id: I74b231956ad0884528b17720cbfa3639281af9a3
Signed-off-by: Balakrishna Godavarthi <quic_bgodavar@quicinc.com>
Signed-off-by: Cheney Ni <cheneyni@google.com>
-rw-r--r-- | btpower.c | 108 | ||||
-rw-r--r-- | linux/btpower.h | 14 |
2 files changed, 122 insertions, 0 deletions
@@ -249,6 +249,36 @@ static void btpower_uart_transport_locked(struct btpower_platform_data *drvdata, exynos_update_ip_idle_status(drvdata->uart_idle_index, !locked); } +#ifdef CONFIG_MSM_BT_OOBS +static irqreturn_t btpower_host_wake_isr(int irq, void *data) +{ + struct btpower_platform_data *drvdata = data; + int host_waking = gpio_get_value(drvdata->bt_gpio_host_wake); + struct kernel_siginfo siginfo; + int rc = 0; + + pr_debug("%s: bt-hostwake-gpio(%d) IRQ(%d) value(%d)\n", __func__, + drvdata->bt_gpio_host_wake, drvdata->irq, host_waking); + + if (drvdata->reftask_obs == NULL) { + pr_info("%s: ignore BT-HOSTWAKE IRQ\n", __func__); + return IRQ_HANDLED; + } + + // Sending signal to HAL layer + memset(&siginfo, 0, sizeof(siginfo)); + siginfo.si_signo = SIGIO; + siginfo.si_code = SI_QUEUE; + siginfo.si_int = host_waking; + rc = send_sig_info(siginfo.si_signo, &siginfo, drvdata->reftask_obs); + if (rc < 0) { + pr_err("%s: failed (%d) to send SIG to HAL(%d)\n", __func__, + rc, drvdata->reftask_obs->pid); + } + return IRQ_HANDLED; +} +#endif + static int bt_vreg_enable(struct bt_power_vreg_data *vreg) { int rc = 0; @@ -491,6 +521,45 @@ static int btpower_gpio_acquire_input(int gpio, const char *label) return rc; } +#ifdef CONFIG_MSM_BT_OOBS +void bt_configure_wakeup_gpios(struct btpower_platform_data *drvdata, int on) +{ + int bt_gpio_dev_wake = drvdata->bt_gpio_dev_wake; + int bt_host_wake_gpio = drvdata->bt_gpio_host_wake; + int rc; + + if (on) { + if (gpio_is_valid(bt_gpio_dev_wake)) { + gpio_set_value(bt_gpio_dev_wake, 1); + pr_debug("%s: BT-ON asserting BT_WAKE(%d)\n", __func__, + bt_gpio_dev_wake); + } + + if (gpio_is_valid(bt_host_wake_gpio)) { + drvdata->irq = gpio_to_irq(bt_host_wake_gpio); + pr_debug("%s: BT-ON bt-host_wake-gpio(%d) IRQ(%d)\n", + __func__, bt_host_wake_gpio, drvdata->irq); + rc = request_irq(drvdata->irq, btpower_host_wake_isr, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "btpower_hostwake_isr", drvdata); + if (rc) + pr_err("%s: unable to request IRQ %d (%d)\n", + __func__, bt_host_wake_gpio, rc); + } + } else { + if (gpio_is_valid(bt_host_wake_gpio)) { + pr_debug("%s: BT-OFF bt-hostwake-gpio(%d) IRQ(%d) value(%d)\n", + __func__, bt_host_wake_gpio, drvdata->irq, + gpio_get_value(bt_host_wake_gpio)); + free_irq(drvdata->irq, drvdata); + } + + if (gpio_is_valid(bt_gpio_dev_wake)) + gpio_set_value(bt_gpio_dev_wake, 0); + } +} +#endif + static int bt_configure_gpios(struct btpower_platform_data *drvdata, bool on) { int rc = 0; @@ -503,6 +572,10 @@ static int bt_configure_gpios(struct btpower_platform_data *drvdata, bool on) bt_reset_gpio, gpio_get_value(bt_reset_gpio), (on ? "True" : "False")); +#ifdef CONFIG_MSM_BT_OOBS + if (!on) + bt_configure_wakeup_gpios(drvdata, on); +#endif /* always reset the controller no metter ON or OFF */ SET_GPIO_SOURCE_STATE(drvdata, bt_reset_gpio, BT_RESET_GPIO, 0); msleep(on ? 100 : 50); @@ -536,6 +609,9 @@ static int bt_configure_gpios(struct btpower_platform_data *drvdata, bool on) } msleep(50); +#ifdef CONFIG_MSM_BT_OOBS + bt_configure_wakeup_gpios(drvdata, on); +#endif /* Check if SW_CTRL is asserted */ SYNC_GPIO_SOURCE_CURRENT(drvdata, bt_sw_ctrl_gpio, BT_SW_CTRL_GPIO); @@ -1045,6 +1121,17 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev, pr_info("%s: wl-reset-gpio not provided in device tree\n", __func__); +#ifdef CONFIG_MSM_BT_OOBS + drvdata->bt_gpio_dev_wake = of_get_named_gpio(pdev->dev.of_node, + "qcom,btwake_gpio", 0); + if (drvdata->bt_gpio_dev_wake < 0) + pr_warn("%s: btwake-gpio not provided in device tree\n", __func__); + + drvdata->bt_gpio_host_wake = of_get_named_gpio(pdev->dev.of_node, + "qcom,bthostwake_gpio", 0); + if (drvdata->bt_gpio_host_wake < 0) + pr_warn("%s: bthostwake_gpio not provided in device tree\n", __func__); +#endif drvdata->bt_gpio_sw_ctrl = of_get_named_gpio(pdev->dev.of_node, "qcom,bt-sw-ctrl-gpio", 0); if (!gpio_is_valid(drvdata->bt_gpio_sw_ctrl)) @@ -1224,6 +1311,27 @@ static long btpower_ioctl(struct file *file, unsigned int cmd, unsigned long arg } switch (cmd) { +#ifdef CONFIG_MSM_BT_OOBS + case BT_CMD_OBS_SIGNAL_TASK: + drvdata->reffilp_obs = file; + drvdata->reftask_obs = get_current(); + pr_info("%s: BT_CMD_OBS_SIGNAL_TASK tid %d filp %pK\n", + __func__, drvdata->reftask_obs->pid, file); + break; + case BT_CMD_OBS_VOTE_CLOCK: + if (!gpio_is_valid(drvdata->bt_gpio_dev_wake)) { + pr_warn("%s: BT_CMD_OBS_VOTE_CLOCK bt_dev_wake_n(%d) not configured\n", + __func__, drvdata->bt_gpio_dev_wake); + return -EIO; + } + pwr_cntrl = (int)arg; + btpower_uart_transport_locked(drvdata, (pwr_cntrl == 1 ? true : false)); + gpio_set_value(drvdata->bt_gpio_dev_wake, pwr_cntrl); + pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK cntrl(%d) %s\n", __func__, + pwr_cntrl, gpio_get_value(drvdata->bt_gpio_dev_wake) ? + "Assert" : "Deassert"); + break; +#endif case BT_CMD_SLIM_TEST: #if IS_ENABLED(CONFIG_BT_SLIM_QCA6390) || \ IS_ENABLED(CONFIG_BT_SLIM_QCA6490) || \ diff --git a/linux/btpower.h b/linux/btpower.h index d1c3330..fa4e837 100644 --- a/linux/btpower.h +++ b/linux/btpower.h @@ -74,6 +74,11 @@ struct btpower_platform_data { int bt_gpio_sys_rst; /* Bluetooth reset gpio */ int wl_gpio_sys_rst; /* Wlan reset gpio */ int bt_gpio_sw_ctrl; /* Bluetooth sw_ctrl gpio */ +#ifdef CONFIG_MSM_BT_OOBS + int bt_gpio_dev_wake; /* Bluetooth bt_wake */ + int bt_gpio_host_wake; /* Bluetooth bt_host_wake */ + int irq; /* Bluetooth host_wake IRQ */ +#endif int bt_gpio_debug; /* Bluetooth debug gpio */ int xo_gpio_clk; /* XO clock gpio*/ @@ -90,6 +95,10 @@ struct btpower_platform_data { struct mbox_chan *mbox_chan; const char *vreg_ipa; bool vreg_ipa_configured; +#ifdef CONFIG_MSM_BT_OOBS + struct file *reffilp_obs; + struct task_struct *reftask_obs; +#endif int uart_idle_index; }; @@ -106,4 +115,9 @@ extern int btpower_aop_mbox_init(struct btpower_platform_data *drvdata); #define BT_CMD_GETVAL_POWER_SRCS 0xbfb1 #define BT_CMD_SET_IPA_TCS_INFO 0xbfc0 +#ifdef CONFIG_MSM_BT_OOBS +#define BT_CMD_OBS_SIGNAL_TASK 0xbfd0 +#define BT_CMD_OBS_VOTE_CLOCK 0xbfd1 +#endif + #endif /* __LINUX_BLUETOOTH_POWER_H */ |