Merge tag 'v3.10.92'
[firefly-linux-kernel-4.4.55.git] / net / rfkill / rfkill-rk.c
old mode 100644 (file)
new mode 100755 (executable)
index dfcb972..cb5c717
@@ -42,6 +42,8 @@
 #include <linux/interrupt.h>
 #include <asm/irq.h>
 #include <linux/suspend.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
 
 #if 0
 #define DBG(x...)   printk(KERN_INFO "[BT_RFKILL]: "x)
@@ -51,7 +53,7 @@
 
 #define LOG(x...)   printk(KERN_INFO "[BT_RFKILL]: "x)
 
-#define BT_WAKEUP_TIMEOUT           3000
+#define BT_WAKEUP_TIMEOUT           10000
 #define BT_IRQ_WAKELOCK_TIMEOUT     10*1000
 
 #define BT_BLOCKED     true
@@ -70,7 +72,7 @@ enum {
 #elif defined (CONFIG_ARCH_RK30)
     #define rk_mux_api_set(name,mode)      rk30_mux_api_set(name,mode)
 #else
-    #define rk_mux_api_set(name,mode)
+    #define rk_mux_api_set(name,mode)      rk30_mux_api_set(name,mode)
 #endif
 
 // RK29+BCM4329, ÆäwifiÓëbtµÄpower¿ØÖƽÅÊǽÓÔÚÒ»ÆðµÄ
@@ -119,6 +121,20 @@ static const char bt_name[] =
         "bcm4329"
 #elif defined(CONFIG_MV8787)
         "mv8787"
+#elif defined(CONFIG_AP6210)
+    #if defined(CONFIG_RKWIFI_26M)
+        "ap6210"
+    #else
+        "ap6210_24M"
+    #endif
+#elif defined(CONFIG_AP6330)
+               "ap6330"
+#elif defined(CONFIG_AP6476)
+               "ap6476"
+#elif defined(CONFIG_AP6493)
+               "ap6493"
+#elif defined(CONFIG_AP6441)
+        "ap6441"
 #else
         "bt_default"
 #endif
@@ -161,9 +177,9 @@ static int rfkill_rk_setup_gpio(struct rfkill_rk_gpio* gpio, int mux, const char
                }
         if (gpio->iomux.name)
         {
-            if (mux==1)
+            if (mux==IOMUX_FGPIO)
                 rk_mux_api_set(gpio->iomux.name, gpio->iomux.fgpio);
-            else if (mux==2)
+            else if (mux==IOMUX_FMUX)
                 rk_mux_api_set(gpio->iomux.name, gpio->iomux.fmux);
             else
                 ;// do nothing
@@ -179,13 +195,17 @@ static int rfkill_rk_setup_wake_irq(struct rfkill_rk_data* rfkill)
     int ret=0;
     struct rfkill_rk_irq* irq = &(rfkill->pdata->wake_host_irq);
     
+#ifndef CONFIG_BK3515A_COMBO
     ret = rfkill_rk_setup_gpio(&irq->gpio, IOMUX_FGPIO, rfkill->pdata->name, "wake_host");
     if (ret) goto fail1;
+#endif
 
     if (gpio_is_valid(irq->gpio.io))
     {
+#ifndef CONFIG_BK3515A_COMBO
         ret = gpio_pull_updown(irq->gpio.io, (irq->gpio.enable==GPIO_LOW)?GPIOPullUp:GPIOPullDown);
         if (ret) goto fail2;
+#endif
         LOG("Request irq for bt wakeup host\n");
         irq->irq = gpio_to_irq(irq->gpio.io);
         sprintf(irq->name, "%s_irq", irq->gpio.name);
@@ -216,7 +236,24 @@ static inline void rfkill_rk_sleep_bt_internal(struct rfkill_rk_data *rfkill, bo
     struct rfkill_rk_gpio *wake = &rfkill->pdata->wake_gpio;
     
     DBG("*** bt sleep: %d ***\n", sleep);
+#ifndef CONFIG_BK3515A_COMBO
     gpio_direction_output(wake->io, sleep?!wake->enable:wake->enable);
+#else
+    if(!sleep)
+    {
+        DBG("HOST_UART0_TX pull down 10us\n");
+        if (rfkill_rk_setup_gpio(wake, IOMUX_FGPIO, rfkill->pdata->name, "wake") != 0) {
+            return;
+        }
+
+        gpio_direction_output(wake->io, wake->enable);
+        udelay(10);
+        gpio_direction_output(wake->io, !wake->enable);
+
+        rk_mux_api_set(wake->iomux.name, wake->iomux.fmux);
+        gpio_free(wake->io);
+    }
+#endif
 }
 
 static void rfkill_rk_delay_sleep_bt(struct work_struct *work)
@@ -280,6 +317,7 @@ static int rfkill_rk_set_power(void *data, bool blocked)
        struct rfkill_rk_data *rfkill = data;
     struct rfkill_rk_gpio *poweron = &rfkill->pdata->poweron_gpio;
     struct rfkill_rk_gpio *reset = &rfkill->pdata->reset_gpio;
+    struct rfkill_rk_gpio* rts = &rfkill->pdata->rts_gpio;
 
     DBG("Enter %s\n", __func__);
 
@@ -287,7 +325,7 @@ static int rfkill_rk_set_power(void *data, bool blocked)
 
        if (false == blocked) { 
         rfkill_rk_sleep_bt(BT_WAKEUP); // ensure bt is wakeup
-        
+
                if (gpio_is_valid(poweron->io))
         {
                        gpio_direction_output(poweron->io, poweron->enable);
@@ -301,6 +339,27 @@ static int rfkill_rk_set_power(void *data, bool blocked)
             msleep(20);
         }
 
+#if defined(CONFIG_AP6210)
+        if (gpio_is_valid(rts->io))
+        {
+            if (rts->iomux.name)
+            {
+                rk_mux_api_set(rts->iomux.name, rts->iomux.fgpio);
+            }
+            LOG("ENABLE UART_RTS\n");
+            gpio_direction_output(rts->io, rts->enable);
+
+            msleep(100);
+
+            LOG("DISABLE UART_RTS\n");
+            gpio_direction_output(rts->io, !rts->enable);
+            if (rts->iomux.name)
+            {
+                rk_mux_api_set(rts->iomux.name, rts->iomux.fmux);
+            }
+        }
+#endif
+
        LOG("bt turn on power\n");
        } else {
 #if WIFI_BT_POWER_TOGGLE
@@ -368,6 +427,16 @@ static int rfkill_rk_pm_prepare(struct device *dev)
     // enable bt wakeup host
     if (gpio_is_valid(wake_host_irq->gpio.io))
     {
+#ifdef CONFIG_BK3515A_COMBO
+        int ret = 0;
+        ret = rfkill_rk_setup_gpio(&wake_host_irq->gpio, IOMUX_FGPIO, rfkill->pdata->name, "wake_host");
+        if (ret)
+            LOG("irq rfkill_rk_setup_gpio failed\n");
+
+        ret = gpio_pull_updown(wake_host_irq->gpio.io, (wake_host_irq->gpio.enable==GPIO_LOW)?GPIOPullUp:GPIOPullDown);
+        if (ret)
+            LOG("irq gpio_pull_updown failed\n");
+#endif
         DBG("enable irq for bt wakeup host\n");
         enable_irq(wake_host_irq->irq);
     }
@@ -399,6 +468,10 @@ static void rfkill_rk_pm_complete(struct device *dev)
         // ¶ø¶à´Î´¥·¢¸ÃÖжÏ
         LOG("** disable irq\n");
         disable_irq(wake_host_irq->irq);
+#ifdef CONFIG_BK3515A_COMBO
+        rk_mux_api_set(wake_host_irq->gpio.iomux.name, wake_host_irq->gpio.iomux.fmux);
+        gpio_free(wake_host_irq->gpio.io);
+#endif
     }
 
     /* Ê¹ÓÃUART_RTS£¬´ËʱÀ¶ÑÀÈç¹ûÓÐÊý¾Ý¾Í»áË͵½UART
@@ -420,11 +493,56 @@ static const struct rfkill_ops rfkill_rk_ops = {
     .set_block = rfkill_rk_set_power,
 };
 
+#define PROC_DIR       "bluetooth/sleep"
+
+static struct proc_dir_entry *bluetooth_dir, *sleep_dir;
+
+static int bluesleep_read_proc_lpm(char *page, char **start, off_t offset,
+                                       int count, int *eof, void *data)
+{
+    *eof = 1;
+    return sprintf(page, "unsupported to read\n");
+}
+
+static int bluesleep_write_proc_lpm(struct file *file, const char *buffer,
+                                       unsigned long count, void *data)
+{
+    return count;
+}
+
+static int bluesleep_read_proc_btwrite(char *page, char **start, off_t offset,
+                                       int count, int *eof, void *data)
+{
+    *eof = 1;
+    return sprintf(page, "unsupported to read\n");
+}
+
+static int bluesleep_write_proc_btwrite(struct file *file, const char *buffer,
+                                       unsigned long count, void *data)
+{
+    char b;
+
+    if (count < 1)
+        return -EINVAL;
+
+    if (copy_from_user(&b, buffer, 1))
+        return -EFAULT;
+
+    DBG("btwrite %c\n", b);
+    /* HCI_DEV_WRITE */
+    if (b != '0') {
+        rfkill_rk_sleep_bt(BT_WAKEUP);
+    }
+
+    return count;
+}
+
 static int rfkill_rk_probe(struct platform_device *pdev)
 {
        struct rfkill_rk_data *rfkill;
        struct rfkill_rk_platform_data *pdata = pdev->dev.platform_data;
        int ret = 0;
+    struct proc_dir_entry *ent;
 
     DBG("Enter %s\n", __func__);
 
@@ -442,6 +560,38 @@ static int rfkill_rk_probe(struct platform_device *pdev)
        rfkill->pdata = pdata;
     g_rfkill = rfkill;
 
+    bluetooth_dir = proc_mkdir("bluetooth", NULL);
+    if (bluetooth_dir == NULL) {
+        LOG("Unable to create /proc/bluetooth directory");
+        return -ENOMEM;
+    }
+
+    sleep_dir = proc_mkdir("sleep", bluetooth_dir);
+    if (sleep_dir == NULL) {
+        LOG("Unable to create /proc/%s directory", PROC_DIR);
+        return -ENOMEM;
+    }
+
+       /* read/write proc entries */
+    ent = create_proc_entry("lpm", 0, sleep_dir);
+    if (ent == NULL) {
+        LOG("Unable to create /proc/%s/lpm entry", PROC_DIR);
+        ret = -ENOMEM;
+        goto fail_alloc;
+    }
+    ent->read_proc = bluesleep_read_proc_lpm;
+    ent->write_proc = bluesleep_write_proc_lpm;
+
+    /* read/write proc entries */
+    ent = create_proc_entry("btwrite", 0, sleep_dir);
+    if (ent == NULL) {
+        LOG("Unable to create /proc/%s/btwrite entry", PROC_DIR);
+        ret = -ENOMEM;
+        goto fail_alloc;
+    }
+    ent->read_proc = bluesleep_read_proc_btwrite;
+    ent->write_proc = bluesleep_write_proc_btwrite;
+
     // ÉêÇëGPIOÒÔ¼°IRQ
     DBG("init gpio\n");
     // ¶ÔÓÚRK29 BCM4329£¬ËüµÄpoweron ioÓëwifi¹²Óã¬ÔÚboadÎļþÖÐÒѾ­request
@@ -454,13 +604,15 @@ static int rfkill_rk_probe(struct platform_device *pdev)
     ret = rfkill_rk_setup_gpio(&pdata->reset_gpio, IOMUX_FGPIO, pdata->name, "reset");
     if (ret) goto fail_poweron;
 
+#ifndef CONFIG_BK3515A_COMBO
     ret = rfkill_rk_setup_gpio(&pdata->wake_gpio, IOMUX_FGPIO, pdata->name, "wake");
     if (ret) goto fail_reset;
+#endif
 
     ret = rfkill_rk_setup_wake_irq(rfkill);
     if (ret) goto fail_wake;
 
-    ret = rfkill_rk_setup_gpio(&(pdata->rts_gpio), IOMUX_FNORMAL, rfkill->pdata->name, "rts");
+    ret = rfkill_rk_setup_gpio(&pdata->rts_gpio, IOMUX_FMUX, rfkill->pdata->name, "rts"); 
     if (ret) goto fail_wake_host_irq;
 
     // ´´½¨²¢×¢²áRFKILLÉ豸
@@ -496,11 +648,15 @@ fail_rts:
 fail_wake_host_irq:
     if (gpio_is_valid(pdata->wake_host_irq.gpio.io)){
         free_irq(pdata->wake_host_irq.irq, rfkill);
+#ifndef CONFIG_BK3515A_COMBO
         gpio_free(pdata->wake_host_irq.gpio.io);
+#endif
     }
 fail_wake:
+#ifndef CONFIG_BK3515A_COMBO
     if (gpio_is_valid(pdata->wake_gpio.io))
         gpio_free(pdata->wake_gpio.io);
+#endif
 fail_reset:
        if (gpio_is_valid(pdata->reset_gpio.io))
                gpio_free(pdata->reset_gpio.io);
@@ -513,6 +669,9 @@ fail_alloc:
        kfree(rfkill);
     g_rfkill = NULL;
 
+       remove_proc_entry("btwrite", sleep_dir);
+       remove_proc_entry("lpm", sleep_dir);
+
        return ret;
 }
 
@@ -535,11 +694,15 @@ static int rfkill_rk_remove(struct platform_device *pdev)
     
     if (gpio_is_valid(rfkill->pdata->wake_host_irq.gpio.io)){
         free_irq(rfkill->pdata->wake_host_irq.irq, rfkill);
+#ifndef CONFIG_BK3515A_COMBO
         gpio_free(rfkill->pdata->wake_host_irq.gpio.io);
+#endif
     }
     
+#ifndef CONFIG_BK3515A_COMBO
     if (gpio_is_valid(rfkill->pdata->wake_gpio.io))
         gpio_free(rfkill->pdata->wake_gpio.io);
+#endif
     
     if (gpio_is_valid(rfkill->pdata->reset_gpio.io))
         gpio_free(rfkill->pdata->reset_gpio.io);