diff options
Diffstat (limited to 'drivers/input/keyboard/samsung-keypad.c')
-rw-r--r-- | drivers/input/keyboard/samsung-keypad.c | 218 |
1 files changed, 205 insertions, 13 deletions
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index f689f49..74581e3 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -23,6 +23,13 @@ #include <linux/slab.h> #include <linux/sched.h> #include <plat/keypad.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/gpio.h> +#include <plat/gpio-cfg.h> + + #define SAMSUNG_KEYIFCON 0x00 #define SAMSUNG_KEYIFSTSCLR 0x04 @@ -56,6 +63,11 @@ /* SAMSUNG_KEYIFFC */ #define SAMSUNG_KEYIFFC_MASK (0x3ff << 0) +extern struct class *sec_class; + +static int key_suspend; +static int key_led_prev; + enum samsung_keypad_type { KEYPAD_TYPE_SAMSUNG, KEYPAD_TYPE_S5PV210, @@ -64,6 +76,7 @@ enum samsung_keypad_type { struct samsung_keypad { struct input_dev *input_dev; struct clk *clk; + struct device *dev; void __iomem *base; wait_queue_head_t wait; bool stopped; @@ -132,16 +145,15 @@ static bool samsung_keypad_report(struct samsung_keypad *keypad, continue; pressed = row_state[col] & (1 << row); - + pressed = pressed ? 1 : 0; dev_dbg(&keypad->input_dev->dev, "key %s, row: %d, col: %d\n", pressed ? "pressed" : "released", row, col); val = MATRIX_SCAN_CODE(row, col, keypad->row_shift); - input_event(input_dev, EV_MSC, MSC_SCAN, val); - input_report_key(input_dev, - keypad->keycodes[val], pressed); + input_event(input_dev, EV_KEY, keypad->keycodes[val], pressed); + printk(KERN_INFO "[KEY]:%d, :%d, %d\n", keypad->keycodes[val], val, pressed); } input_sync(keypad->input_dev); } @@ -158,13 +170,14 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) unsigned int val; bool key_down; + + printk(KERN_INFO "[KEY]samsung_keypad_irq()\n"); + do { val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR); /* Clear interrupt. */ writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); - samsung_keypad_scan(keypad, row_state); - key_down = samsung_keypad_report(keypad, row_state); if (key_down) wait_event_timeout(keypad->wait, keypad->stopped, @@ -175,10 +188,36 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t samsung_keypad_xeint_irq(int irq, void *dev_id) +{ + struct samsung_keypad *keypad = dev_id; + struct input_dev *input_dev = keypad->input_dev; + unsigned int val; + + printk(KERN_INFO "[KEY]samsung_keypad_xeint_irq()\n"); + + input_event(input_dev, EV_KEY, KEY_POWER, 1); + input_event(input_dev, EV_KEY, KEY_POWER, 0); + input_sync(input_dev); + + s3c_gpio_cfgpin(GPIO_KBR_0, S3C_GPIO_SFN(3)); + s3c_gpio_setpull(GPIO_KBR_0, S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(GPIO_KBR_1, S3C_GPIO_SFN(3)); + s3c_gpio_setpull(GPIO_KBR_1, S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(GPIO_KBR_2, S3C_GPIO_SFN(3)); + s3c_gpio_setpull(GPIO_KBR_2, S3C_GPIO_PULL_UP); + s3c_gpio_cfgall_range(GPIO_KBR_3, 2, S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP); + s3c_gpio_cfgall_range(GPIO_KBC_0, 5, S3C_GPIO_SFN(3), S3C_GPIO_PULL_NONE); + + return IRQ_HANDLED; +} + static void samsung_keypad_start(struct samsung_keypad *keypad) { unsigned int val; + printk(KERN_INFO "[KEY]samsung_keypad_start()\n"); + /* Tell IRQ thread that it may poll the device. */ keypad->stopped = false; @@ -197,6 +236,8 @@ static void samsung_keypad_stop(struct samsung_keypad *keypad) { unsigned int val; + printk(KERN_INFO "[KEY]samsung_keypad_stop()\n"); + /* Signal IRQ thread to stop polling and disable the handler. */ keypad->stopped = true; wake_up(&keypad->wait); @@ -235,6 +276,76 @@ static void samsung_keypad_close(struct input_dev *input_dev) samsung_keypad_stop(keypad); } +static ssize_t key_disable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +/* struct samsung_keypad *keypad = dev_get_drvdata(dev);*/ + return 0; + +} + +static ssize_t key_disable_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ +/* struct samsung_keypad *keypad = dev_get_drvdata(dev);*/ + + return 0; +} + +static ssize_t key_pressed_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct samsung_keypad *keypad = dev_get_drvdata(dev); + return 0; +} + +static ssize_t key_led_onoff(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + int data; + struct regulator *regulator; + regulator = regulator_get(NULL, "VREG_KEY"); + if (IS_ERR(regulator)) + return 0; + sscanf(buf, "%d\n", &data); + + if (key_led_prev == data || key_suspend == 1) + return 0; + if (data) { + regulator_enable(regulator); + printk(KERN_INFO "[KEY] key_led_on\n"); + } + else { + regulator_disable(regulator); + printk(KERN_INFO "[KEY] key_led_off\n"); + } + key_led_prev = data; + regulator_put(regulator); + mdelay(70); + return 0; +} + +static DEVICE_ATTR(disable_key, S_IRUGO | S_IWUSR | S_IWGRP, + key_disable_show, key_disable_store); +static DEVICE_ATTR(key_pressed, S_IRUGO | S_IWUSR | S_IWGRP, + key_pressed_show, NULL); +static DEVICE_ATTR(keyled_onoff, S_IRUGO | S_IWUSR | S_IWGRP, + NULL, key_led_onoff); + +static struct attribute *key_attributes[] = { + &dev_attr_disable_key.attr, + &dev_attr_key_pressed.attr, + &dev_attr_keyled_onoff.attr, + NULL, +}; + +static struct attribute_group key_attr_group = { + .attrs = key_attributes, +}; + + static int __devinit samsung_keypad_probe(struct platform_device *pdev) { const struct samsung_keypad_platdata *pdata; @@ -245,6 +356,7 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) unsigned int row_shift; unsigned int keymap_size; int error; + int ret; pdata = pdev->dev.platform_data; if (!pdata) { @@ -304,6 +416,11 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) init_waitqueue_head(&keypad->wait); input_dev->name = pdev->name; + #if defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON) + input_dev->phys = "grande_3x4_keypad/input0"; + #else + input_dev->phys = "samsung-keypad/input0"; + #endif input_dev->id.bustype = BUS_HOST; input_dev->dev.parent = &pdev->dev; input_set_drvdata(input_dev, keypad); @@ -311,11 +428,17 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) input_dev->open = samsung_keypad_open; input_dev->close = samsung_keypad_close; - input_dev->evbit[0] = BIT_MASK(EV_KEY); + + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_LED, input_dev->evbit); + set_bit(LED_MISC, input_dev->ledbit); + set_bit(EV_KEY, input_dev->evbit); if (!pdata->no_autorepeat) - input_dev->evbit[0] |= BIT_MASK(EV_REP); + set_bit(EV_REP, input_dev->evbit); - input_set_capability(input_dev, EV_MSC, MSC_SCAN); + + /* when sleep => wakeup, we want to report key-value as KEY_POWER */ + input_set_capability(input_dev, EV_KEY, KEY_POWER); input_dev->keycode = keypad->keycodes; input_dev->keycodesize = sizeof(keypad->keycodes[0]); @@ -343,6 +466,21 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, pdata->wakeup); platform_set_drvdata(pdev, keypad); + /*sysfs*/ + keypad->dev = device_create(sec_class, NULL, 0, NULL, "sec_keypad"); + if (IS_ERR(keypad->dev)) { + printk(KERN_ERR "Failed to create device(tkey_i2c->dev)!\n"); + input_unregister_device(input_dev); + } else { + dev_set_drvdata(keypad->dev, keypad); + ret = sysfs_create_group(&keypad->dev->kobj, + &key_attr_group); + if (ret) { + printk(KERN_ERR + "[Key]: failed to create sysfs group\n"); + } + } + return 0; err_free_irq: @@ -381,7 +519,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#if 1 /*CONFIG_PM*/ static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad, bool enable) { @@ -410,13 +548,56 @@ static int samsung_keypad_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct samsung_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; + int irq; + int error; + + printk(KERN_INFO "[KEY] samsung_keypad_suspend()\n"); mutex_lock(&input_dev->mutex); if (input_dev->users) samsung_keypad_stop(keypad); - samsung_keypad_toggle_wakeup(keypad, true); +/* samsung_keypad_toggle_wakeup(keypad, true); */ + + s3c_gpio_cfgpin(GPIO_KBR_0, S3C_GPIO_SFN(0xf)); + s3c_gpio_setpull(GPIO_KBR_0, S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(GPIO_KBR_1, S3C_GPIO_SFN(0xf)); + s3c_gpio_setpull(GPIO_KBR_1, S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(GPIO_KBR_2, S3C_GPIO_SFN(0xf)); + s3c_gpio_setpull(GPIO_KBR_2, S3C_GPIO_PULL_UP); + s3c_gpio_cfgall_range(GPIO_KBR_3, 2, S3C_GPIO_SFN(0xf), S3C_GPIO_PULL_UP); + s3c_gpio_cfgall_range(GPIO_KBC_0, 5, S3C_GPIO_OUTPUT, S3C_GPIO_PULL_DOWN); + + irq = gpio_to_irq(GPIO_KBR_0); + /*printk(KERN_INFO "[KEY] KP_ROW[2] : %d\n", irq); // KBR(0)*/ + error = request_threaded_irq(irq, NULL, samsung_keypad_xeint_irq, + IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keypad); + enable_irq_wake(irq); + + irq = gpio_to_irq(GPIO_KBR_1); + /*printk(KERN_INFO "[KEY] KP_ROW[4] : %d\n", irq); // KBR(3)*/ + error = request_threaded_irq(irq, NULL, samsung_keypad_xeint_irq, + IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keypad); + enable_irq_wake(irq); + + irq = gpio_to_irq(GPIO_KBR_2); + /*printk(KERN_INFO "[KEY] KP_ROW[8] : %d\n", irq); // KBR(1)*/ + error = request_threaded_irq(irq, NULL, samsung_keypad_xeint_irq, + IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keypad); + enable_irq_wake(irq); + + irq = gpio_to_irq(GPIO_KBR_3); + /*printk(KERN_INFO "[KEY] KP_ROW[11] : %d\n", irq); // KBR(4)*/ + error = request_threaded_irq(irq, NULL, samsung_keypad_xeint_irq, + IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keypad); + enable_irq_wake(irq); + + irq = gpio_to_irq(GPIO_KBR_4); + /*printk(KERN_INFO "[KEY] KP_ROW[12] : %d\n", irq); // KBR(2)*/ + error = request_threaded_irq(irq, NULL, samsung_keypad_xeint_irq, + IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keypad); + enable_irq_wake(irq); mutex_unlock(&input_dev->mutex); @@ -429,15 +610,18 @@ static int samsung_keypad_resume(struct device *dev) struct samsung_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; + printk(KERN_INFO "[KEY]samsung_keypad_resume()\n"); + mutex_lock(&input_dev->mutex); - samsung_keypad_toggle_wakeup(keypad, false); +/* samsung_keypad_toggle_wakeup(keypad, false);*/ if (input_dev->users) samsung_keypad_start(keypad); mutex_unlock(&input_dev->mutex); + key_suspend = 0; return 0; } @@ -449,7 +633,11 @@ static const struct dev_pm_ops samsung_keypad_pm_ops = { static struct platform_device_id samsung_keypad_driver_ids[] = { { + #if defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON) + .name = "grande_3x4_keypad", + #else .name = "samsung-keypad", + #endif .driver_data = KEYPAD_TYPE_SAMSUNG, }, { .name = "s5pv210-keypad", @@ -463,9 +651,13 @@ static struct platform_driver samsung_keypad_driver = { .probe = samsung_keypad_probe, .remove = __devexit_p(samsung_keypad_remove), .driver = { +#if defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON) + .name = "grande_3x4_keypad", +#else .name = "samsung-keypad", +#endif .owner = THIS_MODULE, -#ifdef CONFIG_PM +#if 1 /*CONFIG_PM*/ .pm = &samsung_keypad_pm_ops, #endif }, |