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 defined.

Change-Id: I74b231956ad0884528b17720cbfa3639281af9a3
Bu işleme şunda yer alıyor:
Balakrishna Godavarthi
2022-01-11 20:26:10 +05:30
ebeveyn 1d6e351ae8
işleme 2f0eff54ed
2 değiştirilmiş dosya ile 136 ekleme ve 0 silme

Dosyayı Görüntüle

@@ -7,6 +7,7 @@
#ifndef __LINUX_BLUETOOTH_POWER_H
#define __LINUX_BLUETOOTH_POWER_H
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox/qmp.h>
@@ -58,6 +59,11 @@ struct btpower_platform_data {
int wl_gpio_sys_rst; /* Wlan reset gpio */
int bt_gpio_sw_ctrl; /* Bluetooth sw_ctrl gpio */
int bt_gpio_debug; /* Bluetooth debug 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 xo_gpio_clk; /* XO clock gpio*/
struct device *slim_dev;
struct bt_power_vreg_data *vreg_info; /* VDDIO voltage regulator */
@@ -68,6 +74,10 @@ struct btpower_platform_data {
struct mbox_client mbox_client_data;
struct mbox_chan *mbox_chan;
const char *vreg_ipa;
#ifdef CONFIG_MSM_BT_OOBS
struct file *reffilp_obs;
struct task_struct *reftask_obs;
#endif
};
int btpower_register_slimdev(struct device *dev);
@@ -82,4 +92,9 @@ int btpower_aop_mbox_init(struct btpower_platform_data *pdata);
#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 */

Dosyayı Görüntüle

@@ -227,6 +227,42 @@ static int bt_major;
static int soc_id;
static bool probe_finished;
#ifdef CONFIG_MSM_BT_OOBS
static void btpower_uart_transport_locked(struct btpower_platform_data *drvdata,
bool locked)
{
pr_debug("%s: %s\n", __func__, (locked ? "busy" : "idle"));
}
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;
@@ -420,6 +456,47 @@ retry_gpio_req:
gpio_free(xo_clk_gpio);
}
#ifdef CONFIG_MSM_BT_OOBS
void bt_configure_wakeup_gpios(int on)
{
int bt_gpio_dev_wake = bt_power_pdata->bt_gpio_dev_wake;
int bt_host_wake_gpio = bt_power_pdata->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)) {
bt_power_pdata->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, bt_power_pdata->irq);
rc = request_irq(bt_power_pdata->irq,
btpower_host_wake_isr,
IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING,
"btpower_hostwake_isr", bt_power_pdata);
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, bt_power_pdata->irq,
gpio_get_value(bt_host_wake_gpio));
free_irq(bt_power_pdata->irq, bt_power_pdata);
}
if (gpio_is_valid(bt_gpio_dev_wake))
gpio_set_value(bt_gpio_dev_wake, 0);
}
}
#endif
static int bt_configure_gpios(int on)
{
int rc = 0;
@@ -522,6 +599,9 @@ static int bt_configure_gpios(int on)
btpower_set_xo_clk_gpio_state(false);
}
msleep(50);
#ifdef CONFIG_MSM_BT_OOBS
bt_configure_wakeup_gpios(on);
#endif
/* Check if SW_CTRL is asserted */
if (bt_sw_ctrl_gpio >= 0) {
rc = gpio_direction_input(bt_sw_ctrl_gpio);
@@ -555,6 +635,9 @@ static int bt_configure_gpios(int on)
bt_power_src_status[BT_SW_CTRL_GPIO]);
}
} else {
#ifdef CONFIG_MSM_BT_OOBS
bt_configure_wakeup_gpios(on);
#endif
gpio_set_value(bt_reset_gpio, 0);
msleep(100);
pr_info("BT-OFF:bt-reset-gpio(%d) value(%d)\n",
@@ -934,6 +1017,22 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev)
if (rc < 0)
pr_warn("%s: clock not provided in device tree\n",
__func__);
#ifdef CONFIG_MSM_BT_OOBS
bt_power_pdata->bt_gpio_dev_wake =
of_get_named_gpio(pdev->dev.of_node,
"qcom,btwake_gpio", 0);
if (bt_power_pdata->bt_gpio_dev_wake < 0)
pr_warn("%s: btwake-gpio not provided in device tree\n",
__func__);
bt_power_pdata->bt_gpio_host_wake =
of_get_named_gpio(pdev->dev.of_node,
"qcom,bthostwake_gpio", 0);
if (bt_power_pdata->bt_gpio_host_wake < 0)
pr_warn("%s: bthostwake_gpio not provided in device tree\n",
__func__);
#endif
}
bt_power_pdata->bt_power_setup = bluetooth_power;
@@ -1081,6 +1180,28 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
switch (cmd) {
#ifdef CONFIG_MSM_BT_OOBS
case BT_CMD_OBS_SIGNAL_TASK:
bt_power_pdata->reffilp_obs = file;
bt_power_pdata->reftask_obs = get_current();
pr_info("%s: BT_CMD_OBS_SIGNAL_TASK tid %d filp %pK\n",
__func__, bt_power_pdata->reftask_obs->pid, file);
break;
case BT_CMD_OBS_VOTE_CLOCK:
if (!gpio_is_valid(bt_power_pdata->bt_gpio_dev_wake)) {
pr_warn("%s: BT_CMD_OBS_VOTE_CLOCK bt_dev_wake_n(%d) not configured\n",
__func__, bt_power_pdata->bt_gpio_dev_wake);
return -EIO;
}
pwr_cntrl = (int)arg;
btpower_uart_transport_locked(bt_power_pdata, (pwr_cntrl == 1 ? true :
false));
gpio_set_value(bt_power_pdata->bt_gpio_dev_wake, pwr_cntrl);
pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK cntrl(%d) %s\n", __func__,
pwr_cntrl, gpio_get_value(bt_power_pdata->bt_gpio_dev_wake) ?
"Assert" : "Deassert");
break;
#endif
case BT_CMD_SLIM_TEST:
#if (defined CONFIG_BT_SLIM)
if (!bt_power_pdata->slim_dev) {