]> pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP: Make GPIO switch framework sysfs usage more sensible
authorJuha Yrjola <juha.yrjola@solidboot.com>
Thu, 3 Aug 2006 11:26:30 +0000 (14:26 +0300)
committerJuha Yrjola <juha.yrjola@solidboot.com>
Thu, 3 Aug 2006 11:26:30 +0000 (14:26 +0300)
Now there are three attributes per switch:

- state
- type
- direction

Also added support for an 'activity' type of switch.

Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com>
arch/arm/plat-omap/gpio-switch.c
include/asm-arm/arch-omap/board.h

index f546fcc5092220c3181a9096c0f692d190c70289..f2bda2b18baa8b4679e9f9ca3e291fad7d0efa60 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/plat-omap/gpio-switch.c
  *
- *  Copyright (C) 2004, 2005 Nokia Corporation
+ *  Copyright (C) 2004-2006 Nokia Corporation
  *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
  *         and Paul Mundt <paul.mundt@nokia.com>
  *
@@ -44,26 +44,48 @@ static struct device_driver gpio_sw_driver;
 
 static const char *cover_str[2] = { "open", "closed" };
 static const char *connection_str[2] = { "disconnected", "connected" };
+static const char *activity_str[2] = { "inactive", "active" };
 
 /*
- * GPIO switch state poll delay in ms
+ * GPIO switch state debounce delay in ms
  */
-#define OMAP_GPIO_SW_POLL_DELAY        10
+#define OMAP_GPIO_SW_DEBOUNCE_DELAY    10
 
-static void print_sw_state(struct gpio_switch *sw, int state)
+static const char **get_sw_str(struct gpio_switch *sw)
 {
-       const char **str;
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+               return cover_str;
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+               return connection_str;
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               return activity_str;
+       default:
+               BUG();
+               return NULL;
+       }
+}
 
+static const char *get_sw_type(struct gpio_switch *sw)
+{
        switch (sw->type) {
        case OMAP_GPIO_SWITCH_TYPE_COVER:
-               str = cover_str;
-               break;
+               return "cover";
        case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
-               str = connection_str;
-               break;
+               return "connection";
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               return "activity";
        default:
-               str = NULL;
+               BUG();
+               return NULL;
        }
+}
+
+static void print_sw_state(struct gpio_switch *sw, int state)
+{
+       const char **str;
+
+       str = get_sw_str(sw);
        if (str != NULL)
                printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]);
 }
@@ -79,43 +101,87 @@ static int gpio_sw_get_state(struct gpio_switch *sw)
        return state;
 }
 
-static ssize_t gpio_sw_store(struct device *dev,
-                            struct device_attribute *attr,
-                            const char *buf,
-                            size_t count)
+static ssize_t gpio_sw_state_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t count)
 {
        struct gpio_switch *sw = dev_get_drvdata(dev);
-       int enable = (int)simple_strtoul(buf, NULL, 10);
+       const char **str;
+       char state[16];
+       int enable;
+
+       if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT))
+               return -EPERM;
+
+       if (sscanf(buf, "%15s", state) != 1)
+               return -EINVAL;
+
+       str = get_sw_str(sw);
+       if (strcmp(state, str[0]) == 0)
+               enable = 0;
+       else if (strcmp(state, str[1]) == 0)
+               enable = 1;
+       else
+               return -EINVAL;
+       if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+               enable = !enable;
        omap_set_gpio_dataout(sw->gpio, enable);
+
        return count;
 }
 
-#define gpio_sw_switch_attr(name)                                      \
-static ssize_t gpio_sw_show_##name(struct device *dev,                 \
-                                       struct device_attribute *attr,  \
-                                       char *buf)                      \
-{                                                                      \
-       struct gpio_switch *sw = dev_get_drvdata(dev);                  \
-       return sprintf(buf, "%s\n", name##_str[gpio_sw_get_state(sw)]); \
-}                                                                      \
-static DEVICE_ATTR(name##_switch, S_IRUGO | S_IWUSR,                   \
-                  gpio_sw_show_##name, gpio_sw_store)
+static ssize_t gpio_sw_state_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+       const char **str;
+
+       str = get_sw_str(sw);
+       return sprintf(buf, "%s\n", str[sw->state]);
+}
+
+static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, gpio_sw_state_show,
+                  gpio_sw_state_store);
+
+static ssize_t gpio_sw_type_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", get_sw_type(sw));
+}
+
+static DEVICE_ATTR(type, S_IRUGO, gpio_sw_type_show, NULL);
+
+static ssize_t gpio_sw_direction_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+       int is_output;
+
+       is_output = sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT;
+       return sprintf(buf, "%s\n", is_output ? "output" : "input");
+}
+
+static DEVICE_ATTR(direction, S_IRUGO, gpio_sw_direction_show, NULL);
 
-gpio_sw_switch_attr(cover);
-gpio_sw_switch_attr(connection);
 
 static irqreturn_t gpio_sw_irq_handler(int irq, void *arg, struct pt_regs *regs)
 {
        struct gpio_switch *sw = arg;
 
-       mod_timer(&sw->timer, jiffies + OMAP_GPIO_SW_POLL_DELAY / (1000 / HZ));
+       mod_timer(&sw->timer, jiffies + msecs_to_jiffies(OMAP_GPIO_SW_DEBOUNCE_DELAY));
 
        return IRQ_HANDLED;
 }
 
 static void gpio_sw_timer(unsigned long arg)
 {
-       struct gpio_switch *sw = (struct gpio_switch *)arg;
+       struct gpio_switch *sw = (struct gpio_switch *) arg;
 
        schedule_work(&sw->work);
 }
@@ -123,20 +189,18 @@ static void gpio_sw_timer(unsigned long arg)
 static void gpio_sw_handler(void *data)
 {
        struct gpio_switch *sw = data;
-       int state = gpio_sw_get_state(sw);
+       int state;
 
+       state = gpio_sw_get_state(sw);
        if (sw->state == state)
                return;
 
-       if (sw->type == OMAP_GPIO_SWITCH_TYPE_CONNECTION)
-               sysfs_notify(&sw->pdev.dev.kobj, NULL, "connection");
-       else
-               sysfs_notify(&sw->pdev.dev.kobj, NULL, "cover");
        sw->state = state;
        if (omap_get_gpio_datain(sw->gpio))
                set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_FALLING);
        else
                set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_RISING);
+       sysfs_notify(&sw->pdev.dev.kobj, NULL, "state");
        print_sw_state(sw, state);
 }
 
@@ -144,6 +208,16 @@ static int __init new_switch(struct gpio_switch *sw)
 {
        int r, direction, trigger;
 
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               break;
+       default:
+               printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type);
+               return -EINVAL;
+       }
+
        sw->pdev.name   = sw->name;
        sw->pdev.id     = -1;
 
@@ -166,14 +240,9 @@ static int __init new_switch(struct gpio_switch *sw)
        direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
        omap_set_gpio_direction(sw->gpio, direction);
 
-       switch (sw->type) {
-       case OMAP_GPIO_SWITCH_TYPE_COVER:
-               device_create_file(&sw->pdev.dev, &dev_attr_cover_switch);
-               break;
-       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
-               device_create_file(&sw->pdev.dev, &dev_attr_connection_switch);
-               break;
-       }
+       device_create_file(&sw->pdev.dev, &dev_attr_state);
+       device_create_file(&sw->pdev.dev, &dev_attr_type);
+       device_create_file(&sw->pdev.dev, &dev_attr_direction);
 
        list_add(&sw->node, &gpio_switches);
 
@@ -245,12 +314,9 @@ static void gpio_sw_cleanup(void)
 
                free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
 
-               if (sw->type == OMAP_GPIO_SWITCH_TYPE_CONNECTION)
-                       device_remove_file(&sw->pdev.dev,
-                                          &dev_attr_connection_switch);
-               else
-                       device_remove_file(&sw->pdev.dev,
-                                          &dev_attr_cover_switch);
+               device_remove_file(&sw->pdev.dev, &dev_attr_state);
+               device_remove_file(&sw->pdev.dev, &dev_attr_type);
+               device_remove_file(&sw->pdev.dev, &dev_attr_direction);
 
                platform_device_unregister(&sw->pdev);
                omap_free_gpio(sw->gpio);
index c3f42542d90414ee283d6927f0bf170efd140158..dc5273d50421f15a81f77fad18acd7f9596f66e1 100644 (file)
@@ -117,14 +117,19 @@ struct omap_pwm_led_platform_data {
 };
 
 /* Cover:
- *      high -> closed
- *      low  -> open
+ *     high -> closed
+ *     low  -> open
  * Connection:
- *      high -> connected
- *      low  -> disconnected
+ *     high -> connected
+ *     low  -> disconnected
+ * Activity:
+ *     high -> active
+ *     low  -> inactive
+ *
  */
 #define OMAP_GPIO_SWITCH_TYPE_COVER            0x0000
 #define OMAP_GPIO_SWITCH_TYPE_CONNECTION       0x0001
+#define OMAP_GPIO_SWITCH_TYPE_ACTIVITY         0x0002
 #define OMAP_GPIO_SWITCH_FLAG_INVERTED         0x0001
 #define OMAP_GPIO_SWITCH_FLAG_OUTPUT           0x0002
 struct omap_gpio_switch_config {