|
@@ -227,6 +227,42 @@ static int bt_major;
|
|
static int soc_id;
|
|
static int soc_id;
|
|
static bool probe_finished;
|
|
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)
|
|
static int bt_vreg_enable(struct bt_power_vreg_data *vreg)
|
|
{
|
|
{
|
|
int rc = 0;
|
|
int rc = 0;
|
|
@@ -420,6 +456,47 @@ retry_gpio_req:
|
|
gpio_free(xo_clk_gpio);
|
|
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)
|
|
static int bt_configure_gpios(int on)
|
|
{
|
|
{
|
|
int rc = 0;
|
|
int rc = 0;
|
|
@@ -522,6 +599,9 @@ static int bt_configure_gpios(int on)
|
|
btpower_set_xo_clk_gpio_state(false);
|
|
btpower_set_xo_clk_gpio_state(false);
|
|
}
|
|
}
|
|
msleep(50);
|
|
msleep(50);
|
|
|
|
+#ifdef CONFIG_MSM_BT_OOBS
|
|
|
|
+ bt_configure_wakeup_gpios(on);
|
|
|
|
+#endif
|
|
/* Check if SW_CTRL is asserted */
|
|
/* Check if SW_CTRL is asserted */
|
|
if (bt_sw_ctrl_gpio >= 0) {
|
|
if (bt_sw_ctrl_gpio >= 0) {
|
|
rc = gpio_direction_input(bt_sw_ctrl_gpio);
|
|
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]);
|
|
bt_power_src_status[BT_SW_CTRL_GPIO]);
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
|
|
+#ifdef CONFIG_MSM_BT_OOBS
|
|
|
|
+ bt_configure_wakeup_gpios(on);
|
|
|
|
+#endif
|
|
gpio_set_value(bt_reset_gpio, 0);
|
|
gpio_set_value(bt_reset_gpio, 0);
|
|
msleep(100);
|
|
msleep(100);
|
|
pr_info("BT-OFF:bt-reset-gpio(%d) value(%d)\n",
|
|
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)
|
|
if (rc < 0)
|
|
pr_warn("%s: clock not provided in device tree\n",
|
|
pr_warn("%s: clock not provided in device tree\n",
|
|
__func__);
|
|
__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;
|
|
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) {
|
|
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:
|
|
case BT_CMD_SLIM_TEST:
|
|
#if (defined CONFIG_BT_SLIM)
|
|
#if (defined CONFIG_BT_SLIM)
|
|
if (!bt_power_pdata->slim_dev) {
|
|
if (!bt_power_pdata->slim_dev) {
|