Commit 8295e1c8 authored by Juha Yrjola's avatar Juha Yrjola

ARM: OMAP: Make GPIO switch framework sysfs usage more sensible

Now there are three attributes per switch:

- state
- type
- direction

Also added support for an 'activity' type of switch.
Signed-off-by: default avatarJuha Yrjola <juha.yrjola@solidboot.com>
parent b19974dc
/* /*
* linux/arch/arm/plat-omap/gpio-switch.c * linux/arch/arm/plat-omap/gpio-switch.c
* *
* Copyright (C) 2004, 2005 Nokia Corporation * Copyright (C) 2004-2006 Nokia Corporation
* Written by Juha Yrjl <juha.yrjola@nokia.com> * Written by Juha Yrjl <juha.yrjola@nokia.com>
* and Paul Mundt <paul.mundt@nokia.com> * and Paul Mundt <paul.mundt@nokia.com>
* *
...@@ -44,26 +44,48 @@ static struct device_driver gpio_sw_driver; ...@@ -44,26 +44,48 @@ static struct device_driver gpio_sw_driver;
static const char *cover_str[2] = { "open", "closed" }; static const char *cover_str[2] = { "open", "closed" };
static const char *connection_str[2] = { "disconnected", "connected" }; 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) { switch (sw->type) {
case OMAP_GPIO_SWITCH_TYPE_COVER: case OMAP_GPIO_SWITCH_TYPE_COVER:
str = cover_str; return "cover";
break;
case OMAP_GPIO_SWITCH_TYPE_CONNECTION: case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
str = connection_str; return "connection";
break; case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
return "activity";
default: 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) if (str != NULL)
printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]); 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) ...@@ -79,43 +101,87 @@ static int gpio_sw_get_state(struct gpio_switch *sw)
return state; return state;
} }
static ssize_t gpio_sw_store(struct device *dev, static ssize_t gpio_sw_state_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, const char *buf,
size_t count) size_t count)
{ {
struct gpio_switch *sw = dev_get_drvdata(dev); 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); omap_set_gpio_dataout(sw->gpio, enable);
return count; return count;
} }
#define gpio_sw_switch_attr(name) \ static ssize_t gpio_sw_state_show(struct device *dev,
static ssize_t gpio_sw_show_##name(struct device *dev, \ struct device_attribute *attr,
struct device_attribute *attr, \ char *buf)
char *buf) \ {
{ \ struct gpio_switch *sw = dev_get_drvdata(dev);
struct gpio_switch *sw = dev_get_drvdata(dev); \ const char **str;
return sprintf(buf, "%s\n", name##_str[gpio_sw_get_state(sw)]); \
} \ str = get_sw_str(sw);
static DEVICE_ATTR(name##_switch, S_IRUGO | S_IWUSR, \ return sprintf(buf, "%s\n", str[sw->state]);
gpio_sw_show_##name, gpio_sw_store) }
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) static irqreturn_t gpio_sw_irq_handler(int irq, void *arg, struct pt_regs *regs)
{ {
struct gpio_switch *sw = arg; 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; return IRQ_HANDLED;
} }
static void gpio_sw_timer(unsigned long arg) 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); schedule_work(&sw->work);
} }
...@@ -123,20 +189,18 @@ static void gpio_sw_timer(unsigned long arg) ...@@ -123,20 +189,18 @@ static void gpio_sw_timer(unsigned long arg)
static void gpio_sw_handler(void *data) static void gpio_sw_handler(void *data)
{ {
struct gpio_switch *sw = 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) if (sw->state == state)
return; 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; sw->state = state;
if (omap_get_gpio_datain(sw->gpio)) if (omap_get_gpio_datain(sw->gpio))
set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_FALLING); set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_FALLING);
else else
set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_RISING); set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_RISING);
sysfs_notify(&sw->pdev.dev.kobj, NULL, "state");
print_sw_state(sw, state); print_sw_state(sw, state);
} }
...@@ -144,6 +208,16 @@ static int __init new_switch(struct gpio_switch *sw) ...@@ -144,6 +208,16 @@ static int __init new_switch(struct gpio_switch *sw)
{ {
int r, direction, trigger; 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.name = sw->name;
sw->pdev.id = -1; sw->pdev.id = -1;
...@@ -166,14 +240,9 @@ static int __init new_switch(struct gpio_switch *sw) ...@@ -166,14 +240,9 @@ static int __init new_switch(struct gpio_switch *sw)
direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT); direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
omap_set_gpio_direction(sw->gpio, direction); omap_set_gpio_direction(sw->gpio, direction);
switch (sw->type) { device_create_file(&sw->pdev.dev, &dev_attr_state);
case OMAP_GPIO_SWITCH_TYPE_COVER: device_create_file(&sw->pdev.dev, &dev_attr_type);
device_create_file(&sw->pdev.dev, &dev_attr_cover_switch); device_create_file(&sw->pdev.dev, &dev_attr_direction);
break;
case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
device_create_file(&sw->pdev.dev, &dev_attr_connection_switch);
break;
}
list_add(&sw->node, &gpio_switches); list_add(&sw->node, &gpio_switches);
...@@ -245,12 +314,9 @@ static void gpio_sw_cleanup(void) ...@@ -245,12 +314,9 @@ static void gpio_sw_cleanup(void)
free_irq(OMAP_GPIO_IRQ(sw->gpio), sw); free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
if (sw->type == OMAP_GPIO_SWITCH_TYPE_CONNECTION) device_remove_file(&sw->pdev.dev, &dev_attr_state);
device_remove_file(&sw->pdev.dev, device_remove_file(&sw->pdev.dev, &dev_attr_type);
&dev_attr_connection_switch); device_remove_file(&sw->pdev.dev, &dev_attr_direction);
else
device_remove_file(&sw->pdev.dev,
&dev_attr_cover_switch);
platform_device_unregister(&sw->pdev); platform_device_unregister(&sw->pdev);
omap_free_gpio(sw->gpio); omap_free_gpio(sw->gpio);
......
...@@ -122,9 +122,14 @@ struct omap_pwm_led_platform_data { ...@@ -122,9 +122,14 @@ struct omap_pwm_led_platform_data {
* Connection: * Connection:
* high -> connected * high -> connected
* low -> disconnected * low -> disconnected
* Activity:
* high -> active
* low -> inactive
*
*/ */
#define OMAP_GPIO_SWITCH_TYPE_COVER 0x0000 #define OMAP_GPIO_SWITCH_TYPE_COVER 0x0000
#define OMAP_GPIO_SWITCH_TYPE_CONNECTION 0x0001 #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_INVERTED 0x0001
#define OMAP_GPIO_SWITCH_FLAG_OUTPUT 0x0002 #define OMAP_GPIO_SWITCH_FLAG_OUTPUT 0x0002
struct omap_gpio_switch_config { struct omap_gpio_switch_config {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment