diff options
Diffstat (limited to 'drivers/switch')
-rw-r--r-- | drivers/switch/Kconfig | 17 | ||||
-rw-r--r-- | drivers/switch/Makefile | 5 | ||||
-rw-r--r-- | drivers/switch/switch_class.c | 174 | ||||
-rw-r--r-- | drivers/switch/switch_gpio.c | 172 | ||||
-rwxr-xr-x | drivers/switch/wmt/Kconfig | 16 | ||||
-rwxr-xr-x | drivers/switch/wmt/Makefile | 1 | ||||
-rwxr-xr-x | drivers/switch/wmt/wmt_switch.c | 424 |
7 files changed, 809 insertions, 0 deletions
diff --git a/drivers/switch/Kconfig b/drivers/switch/Kconfig new file mode 100644 index 00000000..b34ad750 --- /dev/null +++ b/drivers/switch/Kconfig @@ -0,0 +1,17 @@ +menuconfig SWITCH + tristate "Switch class support" + help + Say Y here to enable switch class support. This allows + monitoring switches by userspace via sysfs and uevent. + +if SWITCH + +config SWITCH_GPIO + tristate "GPIO Swith support" + depends on GENERIC_GPIO + help + Say Y here to enable GPIO based switch support. + +source "drivers/switch/wmt/Kconfig" + +endif # SWITCH diff --git a/drivers/switch/Makefile b/drivers/switch/Makefile new file mode 100644 index 00000000..3ea7aa05 --- /dev/null +++ b/drivers/switch/Makefile @@ -0,0 +1,5 @@ +# Switch Class Driver +obj-$(CONFIG_SWITCH) += switch_class.o +obj-$(CONFIG_SWITCH_GPIO) += switch_gpio.o + +obj-$(CONFIG_WMT_SWITCH) += wmt/ diff --git a/drivers/switch/switch_class.c b/drivers/switch/switch_class.c new file mode 100644 index 00000000..e05fc259 --- /dev/null +++ b/drivers/switch/switch_class.c @@ -0,0 +1,174 @@ +/* + * drivers/switch/switch_class.c + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * +*/ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/err.h> +#include <linux/switch.h> + +struct class *switch_class; +static atomic_t device_count; + +static ssize_t state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct switch_dev *sdev = (struct switch_dev *) + dev_get_drvdata(dev); + + if (sdev->print_state) { + int ret = sdev->print_state(sdev, buf); + if (ret >= 0) + return ret; + } + return sprintf(buf, "%d\n", sdev->state); +} + +static ssize_t name_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct switch_dev *sdev = (struct switch_dev *) + dev_get_drvdata(dev); + + if (sdev->print_name) { + int ret = sdev->print_name(sdev, buf); + if (ret >= 0) + return ret; + } + return sprintf(buf, "%s\n", sdev->name); +} + +static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, state_show, NULL); +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, name_show, NULL); + +void switch_set_state(struct switch_dev *sdev, int state) +{ + char name_buf[120]; + char state_buf[120]; + char *prop_buf; + char *envp[3]; + int env_offset = 0; + int length; + + if (sdev->state != state) { + sdev->state = state; + + prop_buf = (char *)get_zeroed_page(GFP_KERNEL); + if (prop_buf) { + length = name_show(sdev->dev, NULL, prop_buf); + if (length > 0) { + if (prop_buf[length - 1] == '\n') + prop_buf[length - 1] = 0; + snprintf(name_buf, sizeof(name_buf), + "SWITCH_NAME=%s", prop_buf); + envp[env_offset++] = name_buf; + } + length = state_show(sdev->dev, NULL, prop_buf); + if (length > 0) { + if (prop_buf[length - 1] == '\n') + prop_buf[length - 1] = 0; + snprintf(state_buf, sizeof(state_buf), + "SWITCH_STATE=%s", prop_buf); + envp[env_offset++] = state_buf; + } + envp[env_offset] = NULL; + kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp); + free_page((unsigned long)prop_buf); + } else { + printk(KERN_ERR "out of memory in switch_set_state\n"); + kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE); + } + } +} +EXPORT_SYMBOL_GPL(switch_set_state); + +static int create_switch_class(void) +{ + if (!switch_class) { + switch_class = class_create(THIS_MODULE, "switch"); + if (IS_ERR(switch_class)) + return PTR_ERR(switch_class); + atomic_set(&device_count, 0); + } + + return 0; +} + +int switch_dev_register(struct switch_dev *sdev) +{ + int ret; + + if (!switch_class) { + ret = create_switch_class(); + if (ret < 0) + return ret; + } + + sdev->index = atomic_inc_return(&device_count); + sdev->dev = device_create(switch_class, NULL, + MKDEV(0, sdev->index), NULL, sdev->name); + if (IS_ERR(sdev->dev)) + return PTR_ERR(sdev->dev); + + ret = device_create_file(sdev->dev, &dev_attr_state); + if (ret < 0) + goto err_create_file_1; + ret = device_create_file(sdev->dev, &dev_attr_name); + if (ret < 0) + goto err_create_file_2; + + dev_set_drvdata(sdev->dev, sdev); + sdev->state = 0; + return 0; + +err_create_file_2: + device_remove_file(sdev->dev, &dev_attr_state); +err_create_file_1: + device_destroy(switch_class, MKDEV(0, sdev->index)); + printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name); + + return ret; +} +EXPORT_SYMBOL_GPL(switch_dev_register); + +void switch_dev_unregister(struct switch_dev *sdev) +{ + device_remove_file(sdev->dev, &dev_attr_name); + device_remove_file(sdev->dev, &dev_attr_state); + device_destroy(switch_class, MKDEV(0, sdev->index)); + dev_set_drvdata(sdev->dev, NULL); +} +EXPORT_SYMBOL_GPL(switch_dev_unregister); + +static int __init switch_class_init(void) +{ + return create_switch_class(); +} + +static void __exit switch_class_exit(void) +{ + class_destroy(switch_class); +} + +module_init(switch_class_init); +module_exit(switch_class_exit); + +MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); +MODULE_DESCRIPTION("Switch class driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/switch/switch_gpio.c b/drivers/switch/switch_gpio.c new file mode 100644 index 00000000..7e9faa21 --- /dev/null +++ b/drivers/switch/switch_gpio.c @@ -0,0 +1,172 @@ +/* + * drivers/switch/switch_gpio.c + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/switch.h> +#include <linux/workqueue.h> +#include <linux/gpio.h> + +struct gpio_switch_data { + struct switch_dev sdev; + unsigned gpio; + const char *name_on; + const char *name_off; + const char *state_on; + const char *state_off; + int irq; + struct work_struct work; +}; + +static void gpio_switch_work(struct work_struct *work) +{ + int state; + struct gpio_switch_data *data = + container_of(work, struct gpio_switch_data, work); + + state = gpio_get_value(data->gpio); + switch_set_state(&data->sdev, state); +} + +static irqreturn_t gpio_irq_handler(int irq, void *dev_id) +{ + struct gpio_switch_data *switch_data = + (struct gpio_switch_data *)dev_id; + + schedule_work(&switch_data->work); + return IRQ_HANDLED; +} + +static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf) +{ + struct gpio_switch_data *switch_data = + container_of(sdev, struct gpio_switch_data, sdev); + const char *state; + if (switch_get_state(sdev)) + state = switch_data->state_on; + else + state = switch_data->state_off; + + if (state) + return sprintf(buf, "%s\n", state); + return -1; +} + +static int gpio_switch_probe(struct platform_device *pdev) +{ + struct gpio_switch_platform_data *pdata = pdev->dev.platform_data; + struct gpio_switch_data *switch_data; + int ret = 0; + + if (!pdata) + return -EBUSY; + + switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL); + if (!switch_data) + return -ENOMEM; + + switch_data->sdev.name = pdata->name; + switch_data->gpio = pdata->gpio; + switch_data->name_on = pdata->name_on; + switch_data->name_off = pdata->name_off; + switch_data->state_on = pdata->state_on; + switch_data->state_off = pdata->state_off; + switch_data->sdev.print_state = switch_gpio_print_state; + + ret = switch_dev_register(&switch_data->sdev); + if (ret < 0) + goto err_switch_dev_register; + + ret = gpio_request(switch_data->gpio, pdev->name); + if (ret < 0) + goto err_request_gpio; + + ret = gpio_direction_input(switch_data->gpio); + if (ret < 0) + goto err_set_gpio_input; + + INIT_WORK(&switch_data->work, gpio_switch_work); + + switch_data->irq = gpio_to_irq(switch_data->gpio); + if (switch_data->irq < 0) { + ret = switch_data->irq; + goto err_detect_irq_num_failed; + } + + ret = request_irq(switch_data->irq, gpio_irq_handler, + IRQF_TRIGGER_LOW, pdev->name, switch_data); + if (ret < 0) + goto err_request_irq; + + /* Perform initial detection */ + gpio_switch_work(&switch_data->work); + + return 0; + +err_request_irq: +err_detect_irq_num_failed: +err_set_gpio_input: + gpio_free(switch_data->gpio); +err_request_gpio: + switch_dev_unregister(&switch_data->sdev); +err_switch_dev_register: + kfree(switch_data); + + return ret; +} + +static int __devexit gpio_switch_remove(struct platform_device *pdev) +{ + struct gpio_switch_data *switch_data = platform_get_drvdata(pdev); + + cancel_work_sync(&switch_data->work); + gpio_free(switch_data->gpio); + switch_dev_unregister(&switch_data->sdev); + kfree(switch_data); + + return 0; +} + +static struct platform_driver gpio_switch_driver = { + .probe = gpio_switch_probe, + .remove = __devexit_p(gpio_switch_remove), + .driver = { + .name = "switch-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init gpio_switch_init(void) +{ + return platform_driver_register(&gpio_switch_driver); +} + +static void __exit gpio_switch_exit(void) +{ + platform_driver_unregister(&gpio_switch_driver); +} + +module_init(gpio_switch_init); +module_exit(gpio_switch_exit); + +MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); +MODULE_DESCRIPTION("GPIO Switch driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/switch/wmt/Kconfig b/drivers/switch/wmt/Kconfig new file mode 100755 index 00000000..2495aa26 --- /dev/null +++ b/drivers/switch/wmt/Kconfig @@ -0,0 +1,16 @@ +# +# ZET6221 capacity touch screen driver configuration +# +config WMT_SWITCH + tristate "WMT GPIO Switch Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with switch + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wmt_switch + diff --git a/drivers/switch/wmt/Makefile b/drivers/switch/wmt/Makefile new file mode 100755 index 00000000..1ed1858c --- /dev/null +++ b/drivers/switch/wmt/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_WMT_SWITCH) += wmt_switch.o
diff --git a/drivers/switch/wmt/wmt_switch.c b/drivers/switch/wmt/wmt_switch.c new file mode 100755 index 00000000..b4b9c1d1 --- /dev/null +++ b/drivers/switch/wmt/wmt_switch.c @@ -0,0 +1,424 @@ +/*++ + * + * Copyright c 2010 WonderMedia Technologies, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * WonderMedia Technologies, Inc. + * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C +--*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/version.h> +#include <linux/interrupt.h> +#include <asm/irq.h> +#include <linux/workqueue.h> +#include <linux/switch.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/input.h> +#include <linux/suspend.h> + +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + +#define WMT_SWITCH_TIMER_INTERVAL 250 // ms +#define WMT_WIREDKEY_TIMER_INTERVAL 100 // ms + +#define WMT_WIREDKEY_PLUGIN_DEBOUNCE 2000 // ms +#define WMT_WIREDKEY_PRESS_COUNT 1 + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +struct wmt_switch_priv { + struct work_struct switch_work; + struct timer_list switch_timer; + + struct input_dev *idev; + struct work_struct wiredkey_work; + struct timer_list wiredkey_timer; + struct notifier_block pm_notifier; + + int prepare_suspend; +}; + +struct wmt_switch { + struct list_head list; + int gpio; + int active; + int state; + struct switch_dev switch_dev; +}; + +struct wmt_wiredkey { + struct list_head list; + int gpio; + int active; + unsigned int keycode; + int count; +}; + +static LIST_HEAD(wmt_switch_list); +static LIST_HEAD(wmt_wiredkey_list); + +static void wmt_switch_do_work(struct work_struct *work) +{ + struct wmt_switch_priv *priv = container_of(work, struct wmt_switch_priv, switch_work); + struct wmt_switch *wmt_switch; + int new; + + list_for_each_entry(wmt_switch, &wmt_switch_list, list) { + new = gpio_get_value(wmt_switch->gpio); + if (new != wmt_switch->state) { + if (new == wmt_switch->active) + switch_set_state(&wmt_switch->switch_dev, 1); + else + switch_set_state(&wmt_switch->switch_dev, 0); + + wmt_switch->state = new; + + if (!list_empty(&wmt_wiredkey_list) && !strcmp(wmt_switch->switch_dev.name, "h2w")) { + if (wmt_switch->switch_dev.state > 0) { + // headset plugin, start hook-key detect in 2s for debounce + mod_timer(&priv->wiredkey_timer, jiffies + msecs_to_jiffies(WMT_WIREDKEY_PLUGIN_DEBOUNCE)); + } + else { + // headset plugout, stop hook-key detect + del_timer_sync(&priv->wiredkey_timer); + } + } + } + } +} + +static void wmt_switch_timer_handler(unsigned long data) +{ + struct wmt_switch_priv *priv = (struct wmt_switch_priv *)data; + schedule_work(&priv->switch_work); + mod_timer(&priv->switch_timer, jiffies + msecs_to_jiffies(WMT_SWITCH_TIMER_INTERVAL)); +} + +static void wmt_wiredkey_do_work(struct work_struct *work) +{ + struct wmt_switch_priv *priv = container_of(work, struct wmt_switch_priv, wiredkey_work); + struct wmt_wiredkey *wmt_wiredkey; + int new; + if (priv->prepare_suspend) + return; + list_for_each_entry(wmt_wiredkey, &wmt_wiredkey_list, list) { + new = gpio_get_value(wmt_wiredkey->gpio); + if (new != wmt_wiredkey->active) { + // key release + if (wmt_wiredkey->count > WMT_WIREDKEY_PRESS_COUNT) { + printk("Wired-key(%d): release\n", wmt_wiredkey->keycode); + input_event(priv->idev, EV_KEY, wmt_wiredkey->keycode, 0); + input_sync(priv->idev); + } + wmt_wiredkey->count = 0; // reset press count caused by key-release + } + else { + // key pressed + if (wmt_wiredkey->count == WMT_WIREDKEY_PRESS_COUNT) { + printk("Wired-key(%d): pressed\n", wmt_wiredkey->keycode); + input_event(priv->idev, EV_KEY, wmt_wiredkey->keycode, 1); + input_sync(priv->idev); + } + wmt_wiredkey->count++; // increass press count caused by key-pressed + } + } +} + +static void wmt_wiredkey_timer_handler(unsigned long data) +{ + struct wmt_switch_priv *priv = (struct wmt_switch_priv *)data; + schedule_work(&priv->wiredkey_work); + mod_timer(&priv->wiredkey_timer, jiffies + msecs_to_jiffies(WMT_WIREDKEY_TIMER_INTERVAL)); +} + +static int wmt_switch_pm_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct wmt_switch_priv *priv = container_of(this, struct wmt_switch_priv, pm_notifier); + //return 0;//it goes before driver suspend, well system fails to suspend. + //our timer can't be added again, so move it to driver suspend. 2013-9-30 + switch (event) { + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + break; + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + priv->prepare_suspend = 1;// add 2013-10-21 + //del_timer_sync(&priv->switch_timer); + //del_timer_sync(&priv->wiredkey_timer); + break; + default: + return NOTIFY_DONE; + } + return 0; +} + +static int __devinit wmt_switch_probe(struct platform_device *pdev) +{ + int ret; + struct wmt_switch_priv *priv; + struct wmt_switch *wmt_switch, *next; + struct wmt_wiredkey *wmt_wiredkey, *next2; + + priv = kzalloc(sizeof(struct wmt_switch_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + + list_for_each_entry_safe(wmt_switch, next, &wmt_switch_list, list) { + ret = gpio_request(wmt_switch->gpio, wmt_switch->switch_dev.name); + if (ret < 0) { + printk("Switch(%s): gpio(%d) request failed\n", + wmt_switch->switch_dev.name, wmt_switch->gpio); + list_del_init(&wmt_switch->list); + kfree(wmt_switch); + } + else { + printk("Switch(%s): gpio(%d) request success\n", + wmt_switch->switch_dev.name, wmt_switch->gpio); + gpio_direction_input(wmt_switch->gpio); + wmt_switch->state = -1; + switch_dev_register(&wmt_switch->switch_dev); + } + } + + if (list_empty(&wmt_switch_list)) { + kfree(priv); + return -EINVAL; + } + + list_for_each_entry_safe(wmt_wiredkey, next2, &wmt_wiredkey_list, list) { + ret = gpio_request(wmt_wiredkey->gpio, "Wired-key"); + if (ret < 0) { + printk("Wired-key: gpio(%d) request failed\n", wmt_wiredkey->gpio); + list_del_init(&wmt_wiredkey->list); + kfree(wmt_wiredkey); + } + else { + printk("Wired-key: gpio(%d) request success\n", wmt_wiredkey->gpio); + gpio_direction_input(wmt_wiredkey->gpio); + wmt_wiredkey->count = 0; + } + } + + // register input device for wired-key + priv->idev = input_allocate_device(); + if (priv->idev == NULL) { + printk(KERN_ERR "Wired-key: input_allocate_device failed\n"); + return -ENOMEM; + } + priv->idev->name = "Wired-key"; + priv->idev->phys = "Wired-key"; + set_bit(EV_KEY, priv->idev->evbit); + list_for_each_entry(wmt_wiredkey, &wmt_wiredkey_list, list) { + set_bit(wmt_wiredkey->keycode, priv->idev->keybit); + } + input_register_device(priv->idev); + + // init wired-key devices + INIT_WORK(&priv->wiredkey_work, wmt_wiredkey_do_work); + init_timer(&priv->wiredkey_timer); + priv->wiredkey_timer.data = (unsigned long)priv; + priv->wiredkey_timer.function = wmt_wiredkey_timer_handler; + + // init switch devices + INIT_WORK(&priv->switch_work, wmt_switch_do_work); + init_timer(&priv->switch_timer); + priv->switch_timer.data = (unsigned long)priv; + priv->switch_timer.function = wmt_switch_timer_handler; + mod_timer(&priv->switch_timer, jiffies + msecs_to_jiffies(WMT_SWITCH_TIMER_INTERVAL)); + + // register pm event + priv->pm_notifier.notifier_call = wmt_switch_pm_event; + register_pm_notifier(&priv->pm_notifier); + + return 0; +} + +static int __devexit wmt_switch_remove(struct platform_device *pdev) +{ + struct wmt_switch_priv *priv = platform_get_drvdata(pdev); + struct wmt_switch *wmt_switch, *next; + struct wmt_wiredkey *wmt_wiredkey, *next2; + + unregister_pm_notifier(&priv->pm_notifier); + + del_timer_sync(&priv->switch_timer); + del_timer_sync(&priv->wiredkey_timer); + + list_for_each_entry_safe(wmt_wiredkey, next2, &wmt_wiredkey_list, list) { + gpio_free(wmt_wiredkey->gpio); + list_del_init(&wmt_wiredkey->list); + kfree(wmt_wiredkey); + } + + list_for_each_entry_safe(wmt_switch, next, &wmt_switch_list, list) { + switch_dev_unregister(&wmt_switch->switch_dev); + gpio_free(wmt_switch->gpio); + list_del_init(&wmt_switch->list); + kfree(wmt_switch); + } + + input_unregister_device(priv->idev); + + kfree(priv); + return 0; +} + +static int wmt_switch_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct wmt_switch_priv *priv = platform_get_drvdata(pdev); + printk("<<<< %s\n", __FUNCTION__); + del_timer_sync(&priv->wiredkey_timer); + del_timer_sync(&priv->switch_timer); + return 0; +} + +static int wmt_switch_resume(struct platform_device *pdev) +{ + struct wmt_switch_priv *priv = platform_get_drvdata(pdev); + struct wmt_switch *wmt_switch; + printk("<<<< %s\n", __FUNCTION__); + priv->prepare_suspend = 0;//add 2013-10-21 + + mod_timer(&priv->switch_timer, jiffies + msecs_to_jiffies(500)); + + // if headset plugin, start hook-key detect + list_for_each_entry(wmt_switch, &wmt_switch_list, list) { + if (!list_empty(&wmt_wiredkey_list) && !strcmp(wmt_switch->switch_dev.name, "h2w")) { + if (wmt_switch->switch_dev.state > 0) + mod_timer(&priv->wiredkey_timer, jiffies + msecs_to_jiffies(WMT_WIREDKEY_PLUGIN_DEBOUNCE)); + } + + if (!strcmp(wmt_switch->switch_dev.name, "rotation") && !wmt_switch->active) + { + wmt_gpio_setpull(wmt_switch->gpio, WMT_GPIO_PULL_UP); + } + } + return 0; +} + +static struct platform_driver wmt_switch_driver = { + .driver = { + .name = "wmt-switch", + .owner = THIS_MODULE, + }, + .probe = wmt_switch_probe, + .remove = __devexit_p(wmt_switch_remove), + .suspend = wmt_switch_suspend, + .resume = wmt_switch_resume, +}; + +static __init int wmt_switch_init(void) +{ + int ret, gpio, active, keycode; + char buf[128]; + int len = ARRAY_SIZE(buf); + struct wmt_switch *wmt_switch; + struct wmt_wiredkey *wmt_wiredkey; + + ret = wmt_getsyspara("wmt.switch.sim", buf, &len); + if (ret == 0) { + sscanf(buf, "%d:%d", &gpio, &active); + if (gpio_is_valid(gpio)) { + wmt_switch = kzalloc(sizeof(*wmt_switch), GFP_KERNEL); + if (wmt_switch) { + wmt_switch->switch_dev.name = "sim"; + wmt_switch->gpio = gpio; + wmt_switch->active = active; + list_add_tail(&wmt_switch->list, &wmt_switch_list); + } + } + } + + ret = wmt_getsyspara("wmt.switch.sim2", buf, &len); + if (ret == 0) { + sscanf(buf, "%d:%d", &gpio, &active); + if (gpio_is_valid(gpio)) { + wmt_switch = kzalloc(sizeof(*wmt_switch), GFP_KERNEL); + if (wmt_switch) { + wmt_switch->switch_dev.name = "sim2"; + wmt_switch->gpio = gpio; + wmt_switch->active = active; + list_add_tail(&wmt_switch->list, &wmt_switch_list); + } + } + } + + ret = wmt_getsyspara("wmt.switch.hs", buf, &len); + if (ret == 0) { + sscanf(buf, "%d:%d", &gpio, &active); + if (gpio_is_valid(gpio)) { + wmt_switch = kzalloc(sizeof(*wmt_switch), GFP_KERNEL); + if (wmt_switch) { + wmt_switch->switch_dev.name = "h2w"; + wmt_switch->gpio = gpio; + wmt_switch->active = active; + list_add_tail(&wmt_switch->list, &wmt_switch_list); + } + } + } + //add by rambo 2013-8-28, for lock key. + //well also can be used for other ways,so we call emukey. + ret = wmt_getsyspara("wmt.switch.rotation", buf, &len); + if (ret == 0) { + sscanf(buf, "%d:%d", &gpio, &active); + if (gpio_is_valid(gpio)) { + wmt_switch = kzalloc(sizeof(*wmt_switch), GFP_KERNEL); + if (wmt_switch) { + wmt_switch->switch_dev.name = "rotation"; + wmt_switch->gpio = gpio; + wmt_switch->active = active; + list_add_tail(&wmt_switch->list, &wmt_switch_list); + } + if (active == 0) + wmt_gpio_setpull(gpio, WMT_GPIO_PULL_UP); + } + } + + ret = wmt_getsyspara("wmt.wirekey.hook", buf, &len); + if (ret == 0) { + sscanf(buf, "%d:%d:%d", &gpio, &active, &keycode); + if (gpio_is_valid(gpio)) { + wmt_wiredkey = kzalloc(sizeof(*wmt_wiredkey), GFP_KERNEL); + if (wmt_wiredkey) { + wmt_wiredkey->gpio = gpio; + wmt_wiredkey->active = active; + wmt_wiredkey->keycode = keycode; + list_add_tail(&wmt_wiredkey->list, &wmt_wiredkey_list); + } + } + } + + return platform_driver_register(&wmt_switch_driver); +} +module_init(wmt_switch_init); + +static __exit void wmt_switch_exit(void) +{ + platform_driver_unregister(&wmt_switch_driver); +} +module_exit(wmt_switch_exit); + +MODULE_DESCRIPTION("WMT GPIO Switch"); +MODULE_AUTHOR("WonderMedia Technologies, Inc."); +MODULE_LICENSE("GPL"); |