Ver Fonte

Merge "Add out of band sleep support to bluetooth driver" into bt-kernel.lnx.1.0

CNSS_WLAN Service há 3 anos atrás
pai
commit
07f6a6064d
2 ficheiros alterados com 136 adições e 0 exclusões
  1. 15 0
      include/btpower.h
  2. 121 0
      pwr/btpower.c

+ 15 - 0
include/btpower.h

@@ -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 - 0
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) {