add proper uci/hotplug based button handling on atheros and work around boards, where...
[openwrt/svn-archive/archive.git] / target / linux / atheros / files / arch / mips / atheros / reset.c
index 52fa3bbfcf117fd91978f49a8d049e71ced3e4b7..a94954d091ab057b460f967b4df204af8897ae19 100644 (file)
@@ -7,10 +7,9 @@
 #include <linux/netlink.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include "ar531x.h"
-#include "ar5315/ar5315.h"
+#include <ar531x.h>
 
-#define AR531X_RESET_GPIO_IRQ  (AR531X_GPIO_IRQ_BASE + bcfg->resetConfigGpio)
+#define AR531X_RESET_GPIO_IRQ  (AR531X_GPIO_IRQ(bcfg->resetConfigGpio))
 
 struct event_t {
        struct work_struct wq;
@@ -19,6 +18,7 @@ struct event_t {
 };
 
 static struct ar531x_boarddata *bcfg;
+static struct timer_list rst_button_timer;
 
 extern struct sock *uevent_sock;
 extern u64 uevent_next_seqnum(void);
@@ -38,7 +38,7 @@ static void hotplug_button(struct work_struct *wq)
        size_t len;
        char *scratch, *s;
        char buf[128];
-       
+
        event = container_of(wq, struct event_t, wq);
        if (!uevent_sock)
                goto done;
@@ -49,7 +49,7 @@ static void hotplug_button(struct work_struct *wq)
        skb = alloc_skb(len + 2048, GFP_KERNEL);
        if (!skb)
                goto done;
-       
+
        /* add header */
        scratch = skb_put(skb, len);
        sprintf(scratch, "%s@",s);
@@ -72,6 +72,37 @@ done:
        kfree(event);
 }
 
+static int no_release_workaround = 1;
+
+static void
+reset_button_poll(unsigned long unused)
+{
+       struct event_t *event;
+       int gpio = ~0;
+
+       if(!no_release_workaround)
+               return;
+
+       DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
+    gpio &= 1 << (AR531X_RESET_GPIO_IRQ - AR531X_GPIO_IRQ_BASE);
+       if(gpio)
+       {
+               rst_button_timer.expires = jiffies + (HZ / 4);
+               add_timer(&rst_button_timer);
+       } else {
+               event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
+               if (!event)
+               {
+                       printk("Could not alloc hotplug event\n");
+                       return;
+               }
+               event->set = 0;
+               event->jiffies = jiffies;
+               INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
+               schedule_work(&event->wq);
+       }
+}
+
 static irqreturn_t button_handler(int irq, void *dev_id)
 {
        static int pressed = 0;
@@ -81,26 +112,33 @@ static irqreturn_t button_handler(int irq, void *dev_id)
        event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
        if (!event)
                return IRQ_NONE;
-       
+
        pressed = !pressed;
 
        DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
        gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE);
 
        event->set = gpio;
+       if(!event->set)
+               no_release_workaround = 0;
+
        event->jiffies = jiffies;
 
        INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
        schedule_work(&event->wq);
 
        seen = jiffies;
-
+       if(event->set && no_release_workaround)
+       {
+               rst_button_timer.expires = jiffies + (HZ / 4);
+               add_timer(&rst_button_timer);
+       }
        return IRQ_HANDLED;
 }
 
 void ar531x_disable_reset_button(void)
 {
-       disable_irq(AR531X_RESET_GPIO_IRQ);     
+       disable_irq(AR531X_RESET_GPIO_IRQ);
 }
 
 EXPORT_SYMBOL(ar531x_disable_reset_button);
@@ -110,7 +148,12 @@ int __init ar531x_init_reset(void)
        bcfg = (struct ar531x_boarddata *) board_config;
 
        seen = jiffies;
-       
+
+       init_timer(&rst_button_timer);
+       rst_button_timer.function = reset_button_poll;
+       rst_button_timer.expires = jiffies + HZ / 50;
+       add_timer(&rst_button_timer);
+
        request_irq(AR531X_RESET_GPIO_IRQ, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL);
 
        return 0;