bluetooth: enable lpm support for atheros SoC.

Low power mode support is enabled for Atheros SoC

Change-Id: I2bf753898a52a205cc9d074b4e1962c5e50e78a1
diff --git a/libbt-vendor/Android.mk b/libbt-vendor/Android.mk
index c446d02..445bbd6 100644
--- a/libbt-vendor/Android.mk
+++ b/libbt-vendor/Android.mk
@@ -34,6 +34,11 @@
         $(LOCAL_PATH)/include \
         $(BDROID_DIR)/hci/include
 
+ifeq ($(BOARD_HAS_QCA_BT_AR3002), true)
+LOCAL_C_FLAGS := \
+        -DBT_WAKE_VIA_PROC
+endif #BOARD_HAS_QCA_BT_AR3002
+
 LOCAL_SHARED_LIBRARIES := \
         libcutils \
         liblog
diff --git a/libbt-vendor/include/bt_vendor_ar3k.h b/libbt-vendor/include/bt_vendor_ar3k.h
index 646948d..038f454 100644
--- a/libbt-vendor/include/bt_vendor_ar3k.h
+++ b/libbt-vendor/include/bt_vendor_ar3k.h
@@ -34,6 +34,16 @@
 #define TRUE   (!FALSE)
 #endif
 
+/* proc fs node for enable/disable lpm mode */
+#ifndef VENDOR_LPM_PROC_NODE
+#define VENDOR_LPM_PROC_NODE "/sys/module/hci_uart/parameters/ath_lpm"
+#endif
+
+/* proc fs node for notifying write request */
+#ifndef VENDOR_BTWRITE_PROC_NODE
+#define VENDOR_BTWRITE_PROC_NODE "/sys/module/hci_uart/parameters/ath_btwrite"
+#endif
+
 // File discriptor using Transport
 extern int fd;
 
diff --git a/libbt-vendor/src/bt_vendor_qcom.c b/libbt-vendor/src/bt_vendor_qcom.c
index d388b89..0d18764 100644
--- a/libbt-vendor/src/bt_vendor_qcom.c
+++ b/libbt-vendor/src/bt_vendor_qcom.c
@@ -48,6 +48,7 @@
 **  Variables
 ******************************************************************************/
 int pFd[2] = {0,};
+
 bt_hci_transport_device_type bt_hci_transport_device;
 
 bt_vendor_callbacks_t *bt_vendor_cbacks = NULL;
@@ -78,16 +79,16 @@
 {
     ALOGI("bt-vendor : init");
     btSocAth = is_bt_soc_ath();
-    if (p_cb == NULL)
-    {
+
+    if (p_cb == NULL) {
         ALOGE("init failed with no user callbacks!");
         return -1;
     }
-     if(btSocAth)
-     {
-         userial_vendor_init();
-     }
-    //upio_init();
+
+    if(btSocAth) {
+        userial_vendor_init();
+        upio_init();
+    }
 
     //vnd_load_conf(VENDOR_LIB_CONF_FILE);
 
@@ -114,42 +115,42 @@
     {
         case BT_VND_OP_POWER_CTRL:
             {
-                if(btSocAth) {
-                    ALOGI("AR3002 ::BT_VND_OP_POWER_CTRL");
-                int *state = (int *) param;
+                if (btSocAth) {
+                    int *state = (int *) param;
 
-                if (*state == BT_VND_PWR_OFF) {
-                    ALOGI("[//]AR3002 UPIO_BT_POWER_OFF");
-                    upio_set_bluetooth_power(UPIO_BT_POWER_OFF);
-                }
-                else if (*state == BT_VND_PWR_ON){
-                    ALOGI("[//]AR3002 UPIO_BT_POWER_ON");
-                    upio_set_bluetooth_power(UPIO_BT_POWER_ON);
-                }
-                }
-               else {
-                nState = *(int *) param;
-                retval = hw_config(nState);
-                if(nState == BT_VND_PWR_ON
-                   && retval == 0
-                   && is_hw_ready() == TRUE){
-                    retval = 0;
+                    ALOGI("BT_VND_OP_POWER_CTRL State: %d ", *state);
+
+                    if (*state == BT_VND_PWR_OFF) {
+                        upio_set_bluetooth_power(UPIO_BT_POWER_OFF);
+                    }
+                    else if (*state == BT_VND_PWR_ON) {
+                        upio_set_bluetooth_power(UPIO_BT_POWER_ON);
+                    }
                 }
                 else {
-                    retval = -1;
+                    nState = *(int *) param;
+
+                    retval = hw_config(nState);
+                    if (nState == BT_VND_PWR_ON
+                         && retval == 0
+                         && is_hw_ready() == TRUE) {
+                        retval = 0;
+                    }
+                    else {
+                        retval = -1;
+                    }
                 }
             }
-            }
             break;
 
         case BT_VND_OP_FW_CFG:
             {
                 // call hciattach to initalize the stack
-                if(bt_vendor_cbacks){
-                   ALOGI("Bluetooth Firmware and smd is initialized");
+                if (bt_vendor_cbacks) {
+                   ALOGI("Bluetooth Firmware and transport is initialized");
                    bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
                 }
-                else{
+                else {
                    ALOGE("Error : hci, smd initialization Error");
                    bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
                 }
@@ -164,58 +165,87 @@
 
         case BT_VND_OP_USERIAL_OPEN:
             {
-             if(btSocAth) {
-                 ALOGI("AR3002 ::BT_VND_OP_USERIAL_OPEN ");
-                 int (*fd_array)[] = (int (*)[]) param;
-                 int fd, idx;
-                 fd = userial_vendor_open((tUSERIAL_CFG *) &userial_init_cfg);
-                 if (fd != -1) {
-                     for (idx=0; idx < CH_MAX; idx++)
-                        (*fd_array)[idx] = fd;
+                 if (btSocAth) {
+                     int (*fd_array)[] = (int (*)[]) param;
+                     int fd, idx;
 
-                     retval = 1;
+                     ALOGI("BT_VND_OP_USERIAL_OPEN ");
+                     fd = userial_vendor_open((tUSERIAL_CFG *) &userial_init_cfg);
+                     if (fd != -1) {
+                         for (idx=0; idx < CH_MAX; idx++)
+                            (*fd_array)[idx] = fd;
+
+                         retval = 1;
+                     }
                  }
-             }
-             else{
-                if(bt_hci_init_transport(pFd) != -1){
-                    int (*fd_array)[] = (int (*) []) param;
+                 else {
+                     if (bt_hci_init_transport(pFd) != -1) {
+                         int (*fd_array)[] = (int (*) []) param;
 
-                        (*fd_array)[CH_CMD] = pFd[0];
-                        (*fd_array)[CH_EVT] = pFd[0];
-                        (*fd_array)[CH_ACL_OUT] = pFd[1];
-                        (*fd_array)[CH_ACL_IN] = pFd[1];
-                }
-                else {
-                    retval = -1;
-                    break;
-                }
-                retval = 2;
-            }
+                         (*fd_array)[CH_CMD] = pFd[0];
+                         (*fd_array)[CH_EVT] = pFd[0];
+                         (*fd_array)[CH_ACL_OUT] = pFd[1];
+                         (*fd_array)[CH_ACL_IN] = pFd[1];
+                     }
+                     else {
+                         retval = -1;
+                         break;
+                     }
+                     retval = 2;
+                 }
 
             }
             break;
 
         case BT_VND_OP_USERIAL_CLOSE:
-            {   if(btSocAth) {
-                 ALOGI("AR3002 ::BT_VND_OP_USERIAL_CLOSE ");
-                 userial_vendor_close();
-                 }
-                 else {
-                 bt_hci_deinit_transport(pFd);
-                 }
+            {
+                if (btSocAth) {
+                    ALOGI("AR3002 ::BT_VND_OP_USERIAL_CLOSE ");
+                    userial_vendor_close();
+                }
+                else {
+                    bt_hci_deinit_transport(pFd);
+                }
             }
             break;
 
         case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
+            {
+                if (btSocAth) {
+                    uint32_t *timeout_ms = (uint32_t *) param;
+                    *timeout_ms = 1000;
+                }
+            }
             break;
 
         case BT_VND_OP_LPM_SET_MODE:
-            {
+            ALOGI("BT_VND_OP_LPM_SET_MODE");
+
+            if(btSocAth) {
+                uint8_t *mode = (uint8_t *) param;
+
+                if (*mode) {
+                    lpm_set_ar3k(UPIO_LPM_MODE, UPIO_ASSERT, 0);
+                }
+                else {
+                    lpm_set_ar3k(UPIO_LPM_MODE, UPIO_DEASSERT, 0);
+                }
+
+                bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS);
+            }
+            else {
                 bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS); //dummy
             }
             break;
 
         case BT_VND_OP_LPM_WAKE_SET_STATE:
+
+            if(btSocAth) {
+                uint8_t *state = (uint8_t *) param;
+                uint8_t wake_assert = (*state == BT_VND_LPM_WAKE_ASSERT) ? \
+                                            UPIO_ASSERT : UPIO_DEASSERT;
+                lpm_set_ar3k(UPIO_BT_WAKE, wake_assert, 0);
+            }
             break;
         case BT_VND_OP_EPILOG:
             {
@@ -239,8 +269,9 @@
 {
     ALOGI("cleanup");
 
-    //upio_cleanup();
-
+    if(btSocAth) {
+        upio_cleanup();
+    }
     bt_vendor_cbacks = NULL;
 }
 
diff --git a/libbt-vendor/src/hardware_ar3k.c b/libbt-vendor/src/hardware_ar3k.c
index 28c81a3..99aa446 100644
--- a/libbt-vendor/src/hardware_ar3k.c
+++ b/libbt-vendor/src/hardware_ar3k.c
@@ -50,6 +50,7 @@
 
 #include "bt_hci_bdroid.h"
 #include "bt_vendor_ar3k.h"
+#include "upio.h"
 
 #define MAX_CNT_RETRY 100
 
@@ -163,6 +164,21 @@
 FILE *stream;
 int tag_count=0;
 
+/* for friendly debugging outpout string */
+static char *lpm_mode[] = {
+    "UNKNOWN",
+    "disabled",
+    "enabled"
+};
+
+static char *lpm_state[] = {
+    "UNKNOWN",
+    "de-asserted",
+    "asserted"
+};
+
+static uint8_t upio_state[UPIO_MAX_COUNT];
+
 typedef struct {
 	uint8_t b[6];
 } __attribute__((packed)) bdaddr_t;
@@ -234,6 +250,8 @@
 }
 #endif
 
+int read_hci_event(int fd, unsigned char* buf, int size);
+
 int is_bt_soc_ath() {
 	int ret = 0;
 	char bt_soc_type[PROPERTY_VALUE_MAX];
@@ -1562,3 +1580,104 @@
 	return n;
 }
 
+void lpm_set_ar3k(uint8_t pio, uint8_t action, uint8_t polarity)
+{
+    int rc;
+    int fd = -1;
+    char buffer;
+
+    ALOGI("lpm mode: %d  action: %d", pio, action);
+
+    switch (pio)
+    {
+        case UPIO_LPM_MODE:
+            if (upio_state[UPIO_LPM_MODE] == action)
+            {
+                ALOGI("LPM is %s already", lpm_mode[action]);
+                return;
+            }
+
+            fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY);
+
+            if (fd < 0)
+            {
+                ALOGE("upio_set : open(%s) for write failed: %s (%d)",
+                        VENDOR_LPM_PROC_NODE, strerror(errno), errno);
+                return;
+            }
+
+            if (action == UPIO_ASSERT)
+            {
+                buffer = '1';
+            }
+            else
+            {
+                buffer = '0';
+            }
+
+            if (write(fd, &buffer, 1) < 0)
+            {
+                ALOGE("upio_set : write(%s) failed: %s (%d)",
+                        VENDOR_LPM_PROC_NODE, strerror(errno),errno);
+            }
+            else
+            {
+                upio_state[UPIO_LPM_MODE] = action;
+                ALOGI("LPM is set to %s", lpm_mode[action]);
+            }
+
+            if (fd >= 0)
+                close(fd);
+
+            break;
+
+        case UPIO_BT_WAKE:
+            /* UPIO_DEASSERT should be allowed because in Rx case assert occur
+             * from the remote side where as deassert  will be initiated from Host
+             */
+            if ((action == UPIO_ASSERT) && (upio_state[UPIO_BT_WAKE] == action))
+            {
+                ALOGI("BT_WAKE is %s already", lpm_state[action]);
+
+                return;
+            }
+
+            if (action == UPIO_DEASSERT)
+              buffer = '0';
+            else
+              buffer = '1';
+
+            fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
+
+            if (fd < 0)
+            {
+                ALOGE("upio_set : open(%s) for write failed: %s (%d)",
+                        VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
+                return;
+            }
+
+            if (write(fd, &buffer, 1) < 0)
+            {
+                ALOGE("upio_set : write(%s) failed: %s (%d)",
+                        VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno);
+            }
+            else
+            {
+                upio_state[UPIO_BT_WAKE] = action;
+                ALOGI("BT_WAKE is set to %s", lpm_state[action]);
+            }
+
+            ALOGI("proc btwrite assertion");
+
+            if (fd >= 0)
+                close(fd);
+
+            break;
+
+        case UPIO_HOST_WAKE:
+            ALOGI("upio_set: UPIO_HOST_WAKE");
+            break;
+    }
+
+}
+