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:
@@ -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 */
|
||||
|
121
pwr/btpower.c
121
pwr/btpower.c
@@ -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) {
|
||||
|
Yeni konuda referans
Bir kullanıcı engelle