Created
September 7, 2017 15:43
-
-
Save craftyguy/e87a1eb9f5fe4ecf1ac343ec5ae4a676 to your computer and use it in GitHub Desktop.
n900 gpio-switch patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- a/arch/arm/plat-omap/Kconfig | |
+++ b/arch/arm/plat-omap/Kconfig | |
@@ -63,6 +63,13 @@ config OMAP_RESET_CLOCKS | |
probably do not want this option enabled until your | |
device drivers work properly. | |
+config OMAP_GPIO_SWITCH | |
+ bool "GPIO switch support" | |
+ default n | |
+ help | |
+ Say Y, if you want to have support for reporting of GPIO | |
+ switches (e.g. cover switches) via sysfs. | |
+ | |
config OMAP_MPU_TIMER | |
bool "Use mpu timer" | |
depends on ARCH_OMAP1 | |
--- a/arch/arm/plat-omap/Makefile | |
+++ b/arch/arm/plat-omap/Makefile | |
@@ -11,3 +11,4 @@ obj-y := sram.o dma.o counter_32k.o | |
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o | |
obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o | |
+obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o | |
--- a/arch/arm/plat-omap/gpio-switch.c | |
+++ b/arch/arm/plat-omap/gpio-switch.c | |
@@ -0,0 +1,571 @@ | |
+/* | |
+ * linux/arch/arm/plat-omap/gpio-switch.c | |
+ * | |
+ * Copyright (C) 2004-2006 Nokia Corporation | |
+ * Written by Juha Yrj�l� <[email protected]> | |
+ * and Paul Mundt <[email protected]> | |
+ * | |
+ * This program is free software; you can redistribute it and/or modify | |
+ * it under the terms of the GNU General Public License version 2 as | |
+ * published by the Free Software Foundation. | |
+ */ | |
+ | |
+#include <linux/sched.h> | |
+#include <linux/init.h> | |
+#include <linux/list.h> | |
+#include <linux/irq.h> | |
+#include <linux/interrupt.h> | |
+#include <linux/module.h> | |
+#include <linux/platform_device.h> | |
+#include <linux/timer.h> | |
+#include <linux/err.h> | |
+#include <linux/gpio.h> | |
+#include <linux/slab.h> | |
+#include <plat/gpio-switch.h> | |
+ | |
+struct gpio_switch { | |
+ char name[14]; | |
+ u16 gpio; | |
+ unsigned flags:4; | |
+ unsigned type:4; | |
+ unsigned state:1; | |
+ unsigned both_edges:1; | |
+ | |
+ u16 debounce_rising; | |
+ u16 debounce_falling; | |
+ | |
+ int disabled; | |
+ | |
+ void (* notify)(void *data, int state); | |
+ void *notify_data; | |
+ | |
+ struct work_struct work; | |
+ struct timer_list timer; | |
+ struct platform_device pdev; | |
+ | |
+ struct list_head node; | |
+ | |
+ bool failed; | |
+}; | |
+ | |
+static LIST_HEAD(gpio_switches); | |
+static struct platform_device *gpio_sw_platform_dev; | |
+static struct platform_driver gpio_sw_driver; | |
+ | |
+static const struct omap_gpio_switch *board_gpio_sw_table; | |
+static int board_gpio_sw_count; | |
+ | |
+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 default debounce delay in ms | |
+ */ | |
+#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE 10 | |
+ | |
+static const char **get_sw_str(struct gpio_switch *sw) | |
+{ | |
+ 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: | |
+ return "cover"; | |
+ case OMAP_GPIO_SWITCH_TYPE_CONNECTION: | |
+ return "connection"; | |
+ case OMAP_GPIO_SWITCH_TYPE_ACTIVITY: | |
+ return "activity"; | |
+ default: | |
+ 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]); | |
+} | |
+ | |
+static int gpio_sw_get_state(struct gpio_switch *sw) | |
+{ | |
+ int state = 0; | |
+ | |
+ if (!sw->failed) | |
+ state = gpio_get_value(sw->gpio); | |
+ | |
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) | |
+ state = !state; | |
+ | |
+ return state; | |
+} | |
+ | |
+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); | |
+ 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) | |
+ sw->state = enable = 0; | |
+ else if (strcmp(state, str[1]) == 0) | |
+ sw->state = enable = 1; | |
+ else | |
+ return -EINVAL; | |
+ | |
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) | |
+ enable = !enable; | |
+ | |
+ if (!sw->failed) | |
+ gpio_set_value(sw->gpio, enable); | |
+ | |
+ return count; | |
+} | |
+ | |
+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; | |
+ | |
+ if (sw->disabled) | |
+ sw->state = gpio_sw_get_state(sw); | |
+ 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); | |
+ | |
+static ssize_t gpio_sw_disable_store(struct device *dev, | |
+ struct device_attribute *attr, | |
+ const char *buf, | |
+ size_t count) | |
+{ | |
+ struct gpio_switch *sw = dev_get_drvdata(dev); | |
+ unsigned long res; | |
+ | |
+ if (kstrtoul(buf, 10, &res) < 0) | |
+ return -EINVAL; | |
+ | |
+ if (!!res == sw->disabled) | |
+ goto out; | |
+ sw->disabled = !!res; | |
+ | |
+ if (sw->failed) | |
+ goto out; | |
+ | |
+ if (res) { | |
+ disable_irq(gpio_to_irq(sw->gpio)); | |
+ } else { | |
+ sw->state = gpio_sw_get_state(sw); | |
+ enable_irq(gpio_to_irq(sw->gpio)); | |
+ } | |
+out: | |
+ return count; | |
+} | |
+ | |
+static ssize_t gpio_sw_disable_show(struct device *dev, | |
+ struct device_attribute *attr, | |
+ char *buf) | |
+{ | |
+ struct gpio_switch *sw = dev_get_drvdata(dev); | |
+ | |
+ return sprintf(buf, "%u\n", sw->disabled); | |
+} | |
+ | |
+static DEVICE_ATTR(disable, S_IRUGO | S_IWUSR, gpio_sw_disable_show, | |
+ gpio_sw_disable_store); | |
+ | |
+static irqreturn_t gpio_sw_irq_handler(int irq, void *arg) | |
+{ | |
+ struct gpio_switch *sw = arg; | |
+ unsigned long timeout; | |
+ int state; | |
+ | |
+ if (!sw->both_edges && !sw->failed) { | |
+ if (gpio_get_value(sw->gpio)) | |
+ irq_set_irq_type(gpio_to_irq(sw->gpio), IRQ_TYPE_EDGE_FALLING); | |
+ else | |
+ irq_set_irq_type(gpio_to_irq(sw->gpio), IRQ_TYPE_EDGE_RISING); | |
+ } | |
+ | |
+ state = gpio_sw_get_state(sw); | |
+ if (sw->state == state) | |
+ return IRQ_HANDLED; | |
+ | |
+ if (state) | |
+ timeout = sw->debounce_rising; | |
+ else | |
+ timeout = sw->debounce_falling; | |
+ if (!timeout) | |
+ schedule_work(&sw->work); | |
+ else | |
+ mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout)); | |
+ | |
+ return IRQ_HANDLED; | |
+} | |
+ | |
+static void gpio_sw_timer(unsigned long arg) | |
+{ | |
+ struct gpio_switch *sw = (struct gpio_switch *) arg; | |
+ | |
+ schedule_work(&sw->work); | |
+} | |
+ | |
+static void gpio_sw_handler(struct work_struct *work) | |
+{ | |
+ struct gpio_switch *sw = container_of(work, struct gpio_switch, work); | |
+ int state; | |
+ | |
+ state = gpio_sw_get_state(sw); | |
+ if (sw->state == state) | |
+ return; | |
+ | |
+ sw->state = state; | |
+ if (sw->notify != NULL) | |
+ sw->notify(sw->notify_data, state); | |
+ sysfs_notify(&sw->pdev.dev.kobj, NULL, "state"); | |
+ print_sw_state(sw, state); | |
+} | |
+ | |
+static void gpio_sw_release(struct device *dev) | |
+{ | |
+} | |
+ | |
+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; | |
+ | |
+ sw->pdev.dev.parent = &gpio_sw_platform_dev->dev; | |
+ sw->pdev.dev.driver = &gpio_sw_driver.driver; | |
+ sw->pdev.dev.release = gpio_sw_release; | |
+ | |
+ r = platform_device_register(&sw->pdev); | |
+ if (r) { | |
+ printk(KERN_ERR "gpio-switch: platform device registration " | |
+ "failed for %s", sw->name); | |
+ return r; | |
+ } | |
+ dev_set_drvdata(&sw->pdev.dev, sw); | |
+ | |
+ if (!sw->failed) | |
+ r = gpio_request(sw->gpio, sw->name); | |
+ else | |
+ r = -EINVAL; | |
+ if (r < 0) { | |
+ printk(KERN_ERR "gpio-switch: gpio_reguest failed for %s %d\n", | |
+ sw->name, sw->gpio); | |
+ sw->failed = true; | |
+ } | |
+ | |
+ /* input: 1, output: 0 */ | |
+ direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT); | |
+ if (!sw->failed) { | |
+ if (direction) { | |
+ gpio_direction_input(sw->gpio); | |
+ sw->state = gpio_sw_get_state(sw); | |
+ } else { | |
+ int state = sw->state = !!(sw->flags & | |
+ OMAP_GPIO_SWITCH_FLAG_OUTPUT_INIT_ACTIVE); | |
+ | |
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) | |
+ state = !state; | |
+ gpio_direction_output(sw->gpio, state); | |
+ } | |
+ } | |
+ | |
+ r = 0; | |
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_state); | |
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_type); | |
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_direction); | |
+ if (direction) | |
+ r |= device_create_file(&sw->pdev.dev, &dev_attr_disable); | |
+ if (r) | |
+ printk(KERN_ERR "gpio-switch: attribute file creation " | |
+ "failed for %s\n", sw->name); | |
+ | |
+ if (!direction) | |
+ return 0; | |
+ | |
+ trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING; | |
+ sw->both_edges = 1; | |
+ | |
+ if (!sw->failed) { | |
+ r = request_irq(gpio_to_irq(sw->gpio), gpio_sw_irq_handler, | |
+ IRQF_SHARED | trigger, sw->name, sw); | |
+ if (r < 0) { | |
+ printk(KERN_ERR "gpio-switch: request_irq() failed " | |
+ "for GPIO %d\n", sw->gpio); | |
+ sw->failed = true; | |
+ gpio_free(sw->gpio); | |
+ } | |
+ } | |
+ | |
+ if (!sw->failed) { | |
+ INIT_WORK(&sw->work, gpio_sw_handler); | |
+ init_timer(&sw->timer); | |
+ | |
+ sw->timer.function = gpio_sw_timer; | |
+ sw->timer.data = (unsigned long)sw; | |
+ } | |
+ | |
+ list_add(&sw->node, &gpio_switches); | |
+ | |
+ return 0; | |
+} | |
+ | |
+static struct gpio_switch * __init find_switch(int gpio, const char *name) | |
+{ | |
+ struct gpio_switch *sw; | |
+ | |
+ list_for_each_entry(sw, &gpio_switches, node) { | |
+ if ((gpio < 0 || sw->gpio != gpio) && | |
+ (name == NULL || strcmp(sw->name, name) != 0)) | |
+ continue; | |
+ | |
+ if (gpio < 0 || name == NULL) | |
+ goto no_check; | |
+ | |
+ if (strcmp(sw->name, name) != 0) | |
+ printk("gpio-switch: name mismatch for %d (%s, %s)\n", | |
+ gpio, name, sw->name); | |
+ else if (sw->gpio != gpio) | |
+ printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n", | |
+ name, gpio, sw->gpio); | |
+no_check: | |
+ return sw; | |
+ } | |
+ return NULL; | |
+} | |
+ | |
+static int __init add_board_switches(void) | |
+{ | |
+ int i; | |
+ | |
+ for (i = 0; i < board_gpio_sw_count; i++) { | |
+ const struct omap_gpio_switch *cfg; | |
+ struct gpio_switch *sw; | |
+ int r; | |
+ | |
+ cfg = board_gpio_sw_table + i; | |
+ if (strlen(cfg->name) > sizeof(sw->name) - 1) | |
+ return -EINVAL; | |
+ /* Check whether we only update an existing switch | |
+ * or add a new switch. */ | |
+ sw = find_switch(cfg->gpio, cfg->name); | |
+ if (sw != NULL) { | |
+ sw->debounce_rising = cfg->debounce_rising; | |
+ sw->debounce_falling = cfg->debounce_falling; | |
+ sw->notify = cfg->notify; | |
+ sw->notify_data = cfg->notify_data; | |
+ continue; | |
+ } else { | |
+ if (cfg->gpio < 0 || cfg->name == NULL) { | |
+ printk("gpio-switch: required switch not " | |
+ "found (%d, %s)\n", cfg->gpio, | |
+ cfg->name); | |
+ continue; | |
+ } | |
+ } | |
+ sw = kzalloc(sizeof(*sw), GFP_KERNEL); | |
+ if (sw == NULL) { | |
+ printk(KERN_ERR "gpio-switch: kmalloc failed\n"); | |
+ return -ENOMEM; | |
+ } | |
+ strlcpy(sw->name, cfg->name, sizeof(sw->name)); | |
+ sw->gpio = cfg->gpio; | |
+ sw->flags = cfg->flags; | |
+ sw->type = cfg->type; | |
+ sw->debounce_rising = cfg->debounce_rising; | |
+ sw->debounce_falling = cfg->debounce_falling; | |
+ sw->notify = cfg->notify; | |
+ sw->notify_data = cfg->notify_data; | |
+ sw->failed = cfg->failed; | |
+ if ((r = new_switch(sw)) < 0) { | |
+ kfree(sw); | |
+ } | |
+ } | |
+ return 0; | |
+} | |
+ | |
+static void gpio_sw_cleanup(void) | |
+{ | |
+ struct gpio_switch *sw = NULL, *old = NULL; | |
+ | |
+ list_for_each_entry(sw, &gpio_switches, node) { | |
+ if (old != NULL) | |
+ kfree(old); | |
+ flush_scheduled_work(); | |
+ del_timer_sync(&sw->timer); | |
+ | |
+ if (!sw->failed) | |
+ free_irq(gpio_to_irq(sw->gpio), sw); | |
+ | |
+ 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); | |
+ | |
+ if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT)) | |
+ device_remove_file(&sw->pdev.dev, &dev_attr_disable); | |
+ | |
+ platform_device_unregister(&sw->pdev); | |
+ if (!sw->failed) | |
+ gpio_free(sw->gpio); | |
+ old = sw; | |
+ } | |
+ kfree(old); | |
+} | |
+ | |
+static void __init report_initial_state(void) | |
+{ | |
+ struct gpio_switch *sw; | |
+ | |
+ list_for_each_entry(sw, &gpio_switches, node) { | |
+ int state = 0; | |
+ | |
+ if (!sw->failed) | |
+ state = gpio_get_value(sw->gpio); | |
+ if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) | |
+ state = !state; | |
+ if (sw->notify != NULL) | |
+ sw->notify(sw->notify_data, state); | |
+ print_sw_state(sw, state); | |
+ } | |
+} | |
+ | |
+static int gpio_sw_remove(struct platform_device *dev) | |
+{ | |
+ return 0; | |
+} | |
+ | |
+static struct platform_driver gpio_sw_driver = { | |
+ .remove = gpio_sw_remove, | |
+ .driver = { | |
+ .name = "gpio-switch", | |
+ }, | |
+}; | |
+ | |
+void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl, | |
+ int count) | |
+{ | |
+ BUG_ON(board_gpio_sw_table != NULL); | |
+ | |
+ board_gpio_sw_table = tbl; | |
+ board_gpio_sw_count = count; | |
+} | |
+ | |
+static int __init gpio_sw_init(void) | |
+{ | |
+ int r; | |
+ | |
+ printk(KERN_INFO "OMAP GPIO switch handler initializing\n"); | |
+ | |
+ r = platform_driver_register(&gpio_sw_driver); | |
+ if (r) | |
+ return r; | |
+ | |
+ gpio_sw_platform_dev = platform_device_register_simple("gpio-switch", | |
+ -1, NULL, 0); | |
+ if (IS_ERR(gpio_sw_platform_dev)) { | |
+ r = PTR_ERR(gpio_sw_platform_dev); | |
+ goto err1; | |
+ } | |
+ | |
+ r = add_board_switches(); | |
+ if (r < 0) | |
+ goto err2; | |
+ | |
+ report_initial_state(); | |
+ | |
+ return 0; | |
+err2: | |
+ gpio_sw_cleanup(); | |
+ platform_device_unregister(gpio_sw_platform_dev); | |
+err1: | |
+ platform_driver_unregister(&gpio_sw_driver); | |
+ return r; | |
+} | |
+ | |
+static void __exit gpio_sw_exit(void) | |
+{ | |
+ gpio_sw_cleanup(); | |
+ platform_device_unregister(gpio_sw_platform_dev); | |
+ platform_driver_unregister(&gpio_sw_driver); | |
+} | |
+ | |
+#ifndef MODULE | |
+late_initcall(gpio_sw_init); | |
+#else | |
+module_init(gpio_sw_init); | |
+#endif | |
+module_exit(gpio_sw_exit); | |
+ | |
+MODULE_AUTHOR("Juha Yrj�l� <[email protected]>, Paul Mundt <[email protected]"); | |
+MODULE_DESCRIPTION("GPIO switch driver"); | |
+MODULE_LICENSE("GPL"); | |
--- a/arch/arm/plat-omap/include/plat/gpio-switch.h | |
+++ b/arch/arm/plat-omap/include/plat/gpio-switch.h | |
@@ -0,0 +1,60 @@ | |
+/* | |
+ * GPIO switch definitions | |
+ * | |
+ * Copyright (C) 2006 Nokia Corporation | |
+ * | |
+ * This program is free software; you can redistribute it and/or modify | |
+ * it under the terms of the GNU General Public License version 2 as | |
+ * published by the Free Software Foundation. | |
+ */ | |
+ | |
+#ifndef __ASM_ARCH_OMAP_GPIO_SWITCH_H | |
+#define __ASM_ARCH_OMAP_GPIO_SWITCH_H | |
+ | |
+#include <linux/types.h> | |
+ | |
+/* Cover: | |
+ * high -> closed | |
+ * low -> open | |
+ * Connection: | |
+ * 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 | |
+#define OMAP_GPIO_SWITCH_FLAG_OUTPUT_INIT_ACTIVE 0x0004 | |
+ | |
+struct omap_gpio_switch { | |
+ const char *name; | |
+ s16 gpio; | |
+ unsigned flags:4; | |
+ unsigned type:4; | |
+ | |
+ /* Time in ms to debounce when transitioning from | |
+ * inactive state to active state. */ | |
+ u16 debounce_rising; | |
+ /* Same for transition from active to inactive state. */ | |
+ u16 debounce_falling; | |
+ | |
+ /* notify board-specific code about state changes */ | |
+ void (* notify)(void *data, int state); | |
+ void *notify_data; | |
+ bool failed; | |
+}; | |
+ | |
+/* Call at init time only */ | |
+#ifdef CONFIG_OMAP_GPIO_SWITCH | |
+extern void omap_register_gpio_switches(const struct omap_gpio_switch *tbl, | |
+ int count); | |
+#else | |
+#define omap_register_gpio_switches(tbl, count) do { } while (0) | |
+#endif | |
+ | |
+#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment