Forráskód Böngészése

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
Balakrishna Godavarthi 3 éve
szülő
commit
2f0eff54ed
2 módosított fájl, 136 hozzáadás és 0 törlés
  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) {