summaryrefslogtreecommitdiff
path: root/drivers/misc/ti-st
diff options
context:
space:
mode:
authorAnita Kar <akar@nvidia.com>2013-04-03 14:53:55 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:07:04 -0700
commita94d329f51de027b78e0eaf9c93f98ec6fa06739 (patch)
treef24f91728f19f5d4fa3c8b39c8ddc2f77e6eb51b /drivers/misc/ti-st
parentce0f36537811cb14409457ae9e8229f569f3c062 (diff)
TI Bluetooth: Adding TI Host Wakeup Driver changes
Signed-off-by: Raghavendra Shenoy Mathav <raghavendra.shenoy@ti.com> Bug 1179655 Change-Id: I904ed2d392b6ff8fbfb00e949f470542387aace4 Signed-off-by: Nagarjuna Kristam <nkristam@nvidia.com> Reviewed-on: http://git-master/r/197395 (cherry picked from commit 4ee03e6f06df0581272a5899267dd295279d2a4c) Signed-off-by: Anita Kar <akar@nvidia.com> Reviewed-on: http://git-master/r/215507 Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'drivers/misc/ti-st')
-rw-r--r--drivers/misc/ti-st/Kconfig28
-rw-r--r--drivers/misc/ti-st/Makefile1
-rw-r--r--drivers/misc/ti-st/st_core.c22
-rwxr-xr-xdrivers/misc/ti-st/st_host_wake.c295
4 files changed, 344 insertions, 2 deletions
diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig
index 9417d76284c4..432551f04280 100644
--- a/drivers/misc/ti-st/Kconfig
+++ b/drivers/misc/ti-st/Kconfig
@@ -30,4 +30,32 @@ config ST_HCI
user-space Bluetooth stacks.
It will provide a character device for user space Bluetooth stack to
send/receive data over shared transport.
+
+config ST_HOST_WAKE
+ tristate "Host wake up driver for protocols registered with ST"
+ depends on TI_ST
+ help
+ This enables the host to wake up whenever a transaction is initiated
+ by the remote side.
+
+config ST_HOST_WAKE_GPS
+ bool "Enable Host wake up driver when GPS registers with ST"
+ depends on ST_HOST_WAKE
+ help
+ This enables the host to wake up whenever GPS transaction is initiated
+ by the remote side.
+
+config ST_HOST_WAKE_FM
+ bool "Enable Host wake up driver when FM registers with ST"
+ depends on ST_HOST_WAKE
+ help
+ This enables the host to wake up whenever FM transaction is initiated
+ by the remote side.
+
+config ST_HOST_WAKE_NFC
+ bool "Enable Host wake up driver when NFC registers with ST"
+ depends on ST_HOST_WAKE
+ help
+ This enables the host to wake up whenever NFC transaction is initiated
+ by the remote side.
endmenu
diff --git a/drivers/misc/ti-st/Makefile b/drivers/misc/ti-st/Makefile
index 2449eade3203..779adc7007d7 100644
--- a/drivers/misc/ti-st/Makefile
+++ b/drivers/misc/ti-st/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_TI_ST) += st_drv.o
st_drv-objs := st_core.o st_kim.o st_ll.o
obj-$(CONFIG_ST_GPS) += gps_drv.o
obj-$(CONFIG_ST_HCI) += tty_hci.o
+obj-$(CONFIG_ST_HOST_WAKE) += st_host_wake.o
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index cc605cd96e3c..1491d1d5d01c 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -46,6 +46,9 @@ static void add_channel_to_table(struct st_data_s *st_gdata,
/* list now has the channel id as index itself */
st_gdata->list[new_proto->chnl_id] = new_proto;
st_gdata->is_registered[new_proto->chnl_id] = true;
+#ifdef CONFIG_ST_HOST_WAKE
+ st_host_wake_notify(new_proto->chnl_id, ST_PROTO_REGISTERED);
+#endif
}
static void remove_channel_from_table(struct st_data_s *st_gdata,
@@ -54,6 +57,9 @@ static void remove_channel_from_table(struct st_data_s *st_gdata,
pr_info("%s: id %d\n", __func__, proto->chnl_id);
/* st_gdata->list[proto->chnl_id] = NULL; */
st_gdata->is_registered[proto->chnl_id] = false;
+#ifdef CONFIG_ST_HOST_WAKE
+ st_host_wake_notify(proto->chnl_id, ST_PROTO_UNREGISTERED);
+#endif
}
/*
@@ -552,6 +558,10 @@ long st_register(struct st_proto_s *new_proto)
/* release lock previously held - re-locked below */
spin_unlock_irqrestore(&st_gdata->lock, flags);
+#ifdef CONFIG_ST_HOST_WAKE
+ /*Enable Voltage regulation*/
+ st_vltg_regulation(ST_VLTG_REG_ENABLE);
+#endif
/* this may take a while to complete
* since it involves BT fw download
*/
@@ -564,6 +574,11 @@ long st_register(struct st_proto_s *new_proto)
st_reg_complete(st_gdata, err);
clear_bit(ST_REG_PENDING, &st_gdata->st_state);
}
+
+#ifdef CONFIG_ST_HOST_WAKE
+ /*Disable Voltage regulation*/
+ st_vltg_regulation(ST_VLTG_REG_DISABLE);
+#endif
return -EINVAL;
}
@@ -603,7 +618,6 @@ long st_register(struct st_proto_s *new_proto)
add_channel_to_table(st_gdata, new_proto);
st_gdata->protos_registered++;
new_proto->write = st_write;
-
/* lock already held before entering else */
spin_unlock_irqrestore(&st_gdata->lock, flags);
return err;
@@ -648,7 +662,6 @@ long st_unregister(struct st_proto_s *proto)
if ((st_gdata->protos_registered == ST_EMPTY) &&
(!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
pr_info(" all chnl_ids unregistered ");
-
/* stop traffic on tty */
if (st_gdata->tty) {
tty_ldisc_flush(st_gdata->tty);
@@ -657,6 +670,11 @@ long st_unregister(struct st_proto_s *proto)
/* all chnl_ids now unregistered */
st_kim_stop(st_gdata->kim_data);
+
+#ifdef CONFIG_ST_HOST_WAKE
+ /*Disable Voltage regulation*/
+ st_vltg_regulation(ST_VLTG_REG_DISABLE);
+#endif
/* disable ST LL */
st_ll_disable(st_gdata);
}
diff --git a/drivers/misc/ti-st/st_host_wake.c b/drivers/misc/ti-st/st_host_wake.c
new file mode 100755
index 000000000000..3246f1563fe2
--- /dev/null
+++ b/drivers/misc/ti-st/st_host_wake.c
@@ -0,0 +1,295 @@
+/*
+ * Shared Transport Host wake up driver
+ * For protocols registered over Shared Transport
+ * Copyright (C) 2011-2012 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <linux/ti_wilink_st.h>
+
+#include <linux/regulator/consumer.h>
+
+#define VERSION "1.2"
+#define FLAG_RESET 0x00
+#define HOST_WAKE 0x01
+#define IRQ_WAKE 0x02
+
+#define CHANNEL_ACL 0x02
+#define CHANNEL_EVT 0x04
+#define CHANNEL_FM 0x08
+#define CHANNEL_GPS 0x09
+#define CHANNEL_NFC 0x0C
+
+struct st_host_wake_info {
+ unsigned host_wake_irq;
+ struct regulator *vdd_3v3;
+ struct regulator *vdd_1v8;
+ unsigned int supp_proto_reg;
+};
+
+static unsigned long flags;
+static struct st_host_wake_info *bsi;
+static char dev_id[12] ="st_host_wake";
+
+void st_host_wake_notify(int chan_id, int reg_state)
+{
+ /* HOST_WAKE to be set after all BT channels including CHANNEL_SCO
+ * is registered
+ */
+ if(chan_id == CHANNEL_ACL || chan_id == CHANNEL_EVT)
+ return;
+
+#ifndef CONFIG_ST_HOST_WAKE_GPS
+ if(chan_id == CHANNEL_GPS) {
+ pr_info("CONFIG_ST_HOST_WAKE_GPS not set hence reject");
+ return;
+ }
+#endif
+
+#ifndef CONFIG_ST_HOST_WAKE_FM
+ if(chan_id == CHANNEL_FM) {
+ pr_info("CONFIG_ST_HOST_WAKE_FM not set hence reject");
+ return;
+ }
+#endif
+
+#ifndef CONFIG_ST_HOST_WAKE_NFC
+ if(chan_id == CHANNEL_NFC) {
+ pr_info("CONFIG_ST_HOST_WAKE_NFC not set hence reject");
+ return;
+ }
+#endif
+ switch(reg_state) {
+ case ST_PROTO_REGISTERED:
+ pr_info("Channel %d registered", chan_id);
+ bsi->supp_proto_reg++;
+ set_bit(HOST_WAKE, &flags);
+ pr_info("HOST_WAKE set");
+ break;
+
+ case ST_PROTO_UNREGISTERED:
+ pr_info("Channel %d un-registered", chan_id);
+ bsi->supp_proto_reg--;
+
+ if(!bsi->supp_proto_reg) {
+ pr_info("All supported protocols un-registered");
+ if(bsi && test_bit(IRQ_WAKE, &flags)) {
+ pr_info("disabling wake_irq after unregister");
+ disable_irq_wake(bsi->host_wake_irq);
+ clear_bit(IRQ_WAKE, &flags);
+ }
+
+ clear_bit(HOST_WAKE, &flags);
+ pr_info("HOST_WAKE cleared");
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL(st_host_wake_notify);
+
+void st_vltg_regulation(int state)
+{
+ pr_info("%s with state %d", __func__, state);
+
+ if(ST_VLTG_REG_ENABLE == state) {
+ if (bsi->vdd_3v3)
+ regulator_enable(bsi->vdd_3v3);
+ if (bsi->vdd_1v8)
+ regulator_enable(bsi->vdd_1v8);
+
+ } else if(ST_VLTG_REG_DISABLE == state) {
+ if (bsi->vdd_3v3)
+ regulator_disable(bsi->vdd_3v3);
+ if (bsi->vdd_1v8)
+ regulator_disable(bsi->vdd_1v8);
+
+ } else {
+ pr_warn("Unknown voltage regulation state");
+ }
+}
+EXPORT_SYMBOL(st_vltg_regulation);
+
+static irqreturn_t st_host_wake_isr(int irq, void *dev_id)
+{
+ pr_debug("%s", __func__);
+
+ return IRQ_HANDLED;
+}
+
+static int st_host_wake_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res = NULL;
+
+ pr_info("TI Host Wakeup Driver [Ver %s]", VERSION);
+
+ bsi = kzalloc(sizeof(struct st_host_wake_info), GFP_KERNEL);
+ if (!bsi)
+ return -ENOMEM;
+
+ bsi->vdd_3v3 = regulator_get(&pdev->dev, "vdd_st_3v3");
+ if (IS_ERR_OR_NULL(bsi->vdd_3v3)) {
+ pr_warn("%s: regulator vdd_st_3v3 not available\n", __func__);
+ bsi->vdd_3v3 = NULL;
+ }
+ bsi->vdd_1v8 = regulator_get(&pdev->dev, "vddio_st_1v8");
+ if (IS_ERR_OR_NULL(bsi->vdd_1v8)) {
+ pr_warn("%s: regulator vddio_st_1v8 not available\n", __func__);
+ bsi->vdd_1v8 = NULL;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "host_wake");
+ if (!res) {
+ pr_err("couldn't find host_wake irq\n");
+ ret = -ENODEV;
+ goto free_bsi;
+ }
+
+ bsi->host_wake_irq = res->start;
+ clear_bit(IRQ_WAKE, &flags);
+
+ if (bsi->host_wake_irq < 0) {
+ pr_err("couldn't find host_wake irq");
+ ret = -ENODEV;
+ goto free_bsi;
+ }
+
+ if (res->flags & IORESOURCE_IRQ_LOWEDGE)
+ ret = request_irq(bsi->host_wake_irq, st_host_wake_isr,
+ IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+ "bluetooth hostwake", dev_id);
+ else
+ ret = request_irq(bsi->host_wake_irq, st_host_wake_isr,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ "bluetooth hostwake", dev_id);
+
+ if (ret < 0) {
+ pr_err("Couldn't acquire HOST_WAKE IRQ");
+ goto free_bsi;
+ }
+
+ clear_bit(HOST_WAKE, &flags);
+ bsi->supp_proto_reg = 0;
+
+ goto finish;
+
+free_bsi:
+ kfree(bsi);
+finish:
+ return ret;
+}
+
+static int st_host_wake_remove(struct platform_device *pdev)
+{
+ pr_debug("%s", __func__);
+
+ free_irq(bsi->host_wake_irq, dev_id);
+
+ if (bsi->vdd_3v3)
+ regulator_put(bsi->vdd_3v3);
+ if (bsi->vdd_1v8)
+ regulator_put(bsi->vdd_1v8);
+
+ kfree(bsi);
+
+ return 0;
+}
+
+static int st_host_wake_resume(struct platform_device *pdev)
+{
+ pr_info("%s", __func__);
+
+ if (test_bit(HOST_WAKE, &flags) && test_bit(IRQ_WAKE, &flags)) {
+ pr_info("disable the host_wake irq");
+ disable_irq_wake(bsi->host_wake_irq);
+ clear_bit(IRQ_WAKE, &flags);
+ }
+
+ return 0;
+}
+
+static int st_host_wake_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ int retval = 0;
+
+ pr_info("%s", __func__);
+
+ if (test_bit(HOST_WAKE, &flags) && (!test_bit(IRQ_WAKE, &flags))) {
+ retval = enable_irq_wake(bsi->host_wake_irq);
+ if (retval < 0) {
+ pr_err("Couldn't enable HOST_WAKE as wakeup"
+ "interrupt retval %d\n", retval);
+ goto fail;
+ }
+ set_bit(IRQ_WAKE, &flags);
+ pr_info("enabled the host_wake irq");
+ }
+fail:
+ return retval;
+}
+
+
+static struct platform_driver st_host_wake_driver = {
+ .probe = st_host_wake_probe,
+ .remove = st_host_wake_remove,
+ .suspend = st_host_wake_suspend,
+ .resume = st_host_wake_resume,
+ .driver = {
+ .name = "st_host_wake",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init st_host_wake_init(void)
+{
+ int retval = 0;
+
+ pr_debug("%s", __func__);
+
+ retval = platform_driver_register(&st_host_wake_driver);
+ if(retval)
+ pr_err("st_host_wake_init failed");
+
+ return retval;
+}
+
+static void __exit st_host_wake_exit(void)
+{
+ pr_debug("%s", __func__);
+
+ if (bsi == NULL)
+ return;
+
+ platform_driver_unregister(&st_host_wake_driver);
+}
+
+module_init(st_host_wake_init);
+module_exit(st_host_wake_exit);
+
+MODULE_DESCRIPTION("TI Host Wakeup Driver [Ver %s]" VERSION);
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif