diff options
Diffstat (limited to 'recipes-kernel/linux/linux-handheld-4.0/locomo/0004-input-convert-LoCoMo-keyboard-driver-to-use-new-loco.patch')
-rw-r--r-- | recipes-kernel/linux/linux-handheld-4.0/locomo/0004-input-convert-LoCoMo-keyboard-driver-to-use-new-loco.patch | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0004-input-convert-LoCoMo-keyboard-driver-to-use-new-loco.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0004-input-convert-LoCoMo-keyboard-driver-to-use-new-loco.patch new file mode 100644 index 0000000..03a2023 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0004-input-convert-LoCoMo-keyboard-driver-to-use-new-loco.patch @@ -0,0 +1,480 @@ +From c546d0c1ae4e7134cfc2668bf4e01753dfb9a98d Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 03:06:46 +0400 +Subject: [PATCH 04/20] input: convert LoCoMo keyboard driver to use new locomo + core + +As LoCoMo is switching to new device model, adapt keyboard driver to +support new locomo core driver. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/input/keyboard/Kconfig | 1 - + drivers/input/keyboard/locomokbd.c | 271 +++++++++++++++++++------------------ + 2 files changed, 143 insertions(+), 129 deletions(-) + +diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig +index a89ba7c..4e20538 100644 +--- a/drivers/input/keyboard/Kconfig ++++ b/drivers/input/keyboard/Kconfig +@@ -337,7 +337,6 @@ config KEYBOARD_LM8333 + + config KEYBOARD_LOCOMO + tristate "LoCoMo Keyboard Support" +- depends on SHARP_LOCOMO + help + Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA + +diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c +index c94d610..eed0a94 100644 +--- a/drivers/input/keyboard/locomokbd.c ++++ b/drivers/input/keyboard/locomokbd.c +@@ -23,37 +23,37 @@ + * + */ + +-#include <linux/slab.h> +-#include <linux/module.h> ++#include <linux/delay.h> + #include <linux/init.h> + #include <linux/input.h> +-#include <linux/delay.h> +-#include <linux/device.h> + #include <linux/interrupt.h> +-#include <linux/ioport.h> +- +-#include <asm/hardware/locomo.h> +-#include <asm/irq.h> +- +-MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); +-MODULE_DESCRIPTION("LoCoMo keyboard driver"); +-MODULE_LICENSE("GPL"); ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/slab.h> ++#include <linux/mfd/locomo.h> + +-#define LOCOMOKBD_NUMKEYS 128 ++/* There is one minor difference between mappings on poodle and collie */ ++#include <asm/mach-types.h> + + #define KEY_ACTIVITY KEY_F16 + #define KEY_CONTACT KEY_F18 + #define KEY_CENTER KEY_F15 + ++#define KB_ROWS 16 ++#define KB_COLS 8 ++#define LOCOMOKBD_NUMKEYS (KB_ROWS * KB_COLS) ++#define SCANCODE(c, r) (((c)<<4) + (r) + 1) ++ + static const unsigned char + locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { + 0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0, /* 0 - 9 */ +- 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT, /* 10 - 19 */ ++ 0, 0, 0, 0, 0, 0, 0, KEY_MENU, 0, KEY_CONTACT, /* 10 - 19 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 29 */ + 0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0, /* 30 - 39 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT, /* 40 - 49 */ + KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T, /* 50 - 59 */ +- KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0, /* 60 - 69 */ ++ KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_KPENTER, 0, 0, /* 60 - 69 */ + KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0, /* 70 - 79 */ + 0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J, /* 80 - 89 */ + KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0, /* 90 - 99 */ +@@ -62,20 +62,14 @@ locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { + KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */ + }; + +-#define KB_ROWS 16 +-#define KB_COLS 8 +-#define KB_ROWMASK(r) (1 << (r)) +-#define SCANCODE(c,r) ( ((c)<<4) + (r) + 1 ) +- + #define KB_DELAY 8 +-#define SCAN_INTERVAL (HZ/10) + + struct locomokbd { + unsigned char keycode[LOCOMOKBD_NUMKEYS]; + struct input_dev *input; +- char phys[32]; + +- unsigned long base; ++ struct regmap *regmap; ++ int irq; + spinlock_t lock; + + struct timer_list timer; +@@ -84,37 +78,33 @@ struct locomokbd { + }; + + /* helper functions for reading the keyboard matrix */ +-static inline void locomokbd_charge_all(unsigned long membase) ++static inline void locomokbd_charge_all(struct locomokbd *locomokbd) + { +- locomo_writel(0x00FF, membase + LOCOMO_KSC); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, 0x00ff); + } + +-static inline void locomokbd_activate_all(unsigned long membase) ++static inline void locomokbd_activate_all(struct locomokbd *locomokbd) + { +- unsigned long r; +- +- locomo_writel(0, membase + LOCOMO_KSC); +- r = locomo_readl(membase + LOCOMO_KIC); +- r &= 0xFEFF; +- locomo_writel(r, membase + LOCOMO_KIC); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, 0); ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x100, 0); + } + +-static inline void locomokbd_activate_col(unsigned long membase, int col) ++static inline void locomokbd_activate_col(struct locomokbd *locomokbd, int col) + { + unsigned short nset; + unsigned short nbset; + +- nset = 0xFF & ~(1 << col); ++ nset = 0xFF & ~BIT(col); + nbset = (nset << 8) + nset; +- locomo_writel(nbset, membase + LOCOMO_KSC); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, nbset); + } + +-static inline void locomokbd_reset_col(unsigned long membase, int col) ++static inline void locomokbd_reset_col(struct locomokbd *locomokbd, int col) + { + unsigned short nbset; + +- nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF; +- locomo_writel(nbset, membase + LOCOMO_KSC); ++ nbset = ((0xFF & ~BIT(col)) << 8) + 0xFF; ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, nbset); + } + + /* +@@ -129,24 +119,25 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd) + unsigned int row, col, rowd; + unsigned long flags; + unsigned int num_pressed; +- unsigned long membase = locomokbd->base; ++ bool esc_pressed = false; + + spin_lock_irqsave(&locomokbd->lock, flags); + +- locomokbd_charge_all(membase); ++ locomokbd_charge_all(locomokbd); + + num_pressed = 0; + for (col = 0; col < KB_COLS; col++) { +- +- locomokbd_activate_col(membase, col); ++ udelay(KB_DELAY); ++ locomokbd_activate_col(locomokbd, col); + udelay(KB_DELAY); + +- rowd = ~locomo_readl(membase + LOCOMO_KIB); ++ regmap_read(locomokbd->regmap, LOCOMO_KIB, &rowd); ++ rowd = ~rowd; + for (row = 0; row < KB_ROWS; row++) { + unsigned int scancode, pressed, key; + + scancode = SCANCODE(col, row); +- pressed = rowd & KB_ROWMASK(row); ++ pressed = rowd & BIT(row); + key = locomokbd->keycode[scancode]; + + input_report_key(locomokbd->input, key, pressed); +@@ -158,29 +149,30 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd) + /* The "Cancel/ESC" key is labeled "On/Off" on + * Collie and Poodle and should suspend the device + * if it was pressed for more than a second. */ +- if (unlikely(key == KEY_ESC)) { +- if (!time_after(jiffies, +- locomokbd->suspend_jiffies + HZ)) +- continue; +- if (locomokbd->count_cancel++ +- != (HZ/SCAN_INTERVAL + 1)) +- continue; +- input_event(locomokbd->input, EV_PWR, +- KEY_SUSPEND, 1); +- locomokbd->suspend_jiffies = jiffies; +- } else +- locomokbd->count_cancel = 0; ++ if (unlikely(key == KEY_ESC)) ++ esc_pressed = true; + } +- locomokbd_reset_col(membase, col); ++ locomokbd_reset_col(locomokbd, col); + } +- locomokbd_activate_all(membase); ++ locomokbd_activate_all(locomokbd); + + input_sync(locomokbd->input); + + /* if any keys are pressed, enable the timer */ + if (num_pressed) +- mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL); ++ mod_timer(&locomokbd->timer, jiffies + msecs_to_jiffies(100)); + else ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10); ++ ++ ++ if (esc_pressed && time_after(jiffies, ++ locomokbd->suspend_jiffies + msecs_to_jiffies(1000))) { ++ if (locomokbd->count_cancel++ > (20)) { ++ input_event(locomokbd->input, EV_PWR, ++ KEY_SUSPEND, 1); ++ locomokbd->suspend_jiffies = jiffies; ++ } ++ } else + locomokbd->count_cancel = 0; + + spin_unlock_irqrestore(&locomokbd->lock, flags); +@@ -192,18 +184,18 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd) + static irqreturn_t locomokbd_interrupt(int irq, void *dev_id) + { + struct locomokbd *locomokbd = dev_id; +- u16 r; ++ unsigned int r; + +- r = locomo_readl(locomokbd->base + LOCOMO_KIC); ++ ++ regmap_read(locomokbd->regmap, LOCOMO_KIC, &r); + if ((r & 0x0001) == 0) + return IRQ_HANDLED; + +- locomo_writel(r & ~0x0100, locomokbd->base + LOCOMO_KIC); /* Ack */ ++ /* Mask and Ack */ ++ regmap_write(locomokbd->regmap, LOCOMO_KIC, r & ~0x110); + +- /** wait chattering delay **/ +- udelay(100); ++ mod_timer(&locomokbd->timer, jiffies + msecs_to_jiffies(1)); + +- locomokbd_scankeyboard(locomokbd); + return IRQ_HANDLED; + } + +@@ -220,47 +212,37 @@ static void locomokbd_timer_callback(unsigned long data) + static int locomokbd_open(struct input_dev *dev) + { + struct locomokbd *locomokbd = input_get_drvdata(dev); +- u16 r; +- +- r = locomo_readl(locomokbd->base + LOCOMO_KIC) | 0x0010; +- locomo_writel(r, locomokbd->base + LOCOMO_KIC); +- return 0; ++ ++ return regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10); + } + + static void locomokbd_close(struct input_dev *dev) + { + struct locomokbd *locomokbd = input_get_drvdata(dev); +- u16 r; +- +- r = locomo_readl(locomokbd->base + LOCOMO_KIC) & ~0x0010; +- locomo_writel(r, locomokbd->base + LOCOMO_KIC); ++ ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x0); + } + +-static int locomokbd_probe(struct locomo_dev *dev) ++static int locomokbd_probe(struct platform_device *dev) + { + struct locomokbd *locomokbd; + struct input_dev *input_dev; + int i, err; + +- locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL); +- input_dev = input_allocate_device(); +- if (!locomokbd || !input_dev) { +- err = -ENOMEM; +- goto err_free_mem; +- } ++ locomokbd = devm_kzalloc(&dev->dev, sizeof(struct locomokbd), ++ GFP_KERNEL); ++ if (!locomokbd) ++ return -ENOMEM; + +- /* try and claim memory region */ +- if (!request_mem_region((unsigned long) dev->mapbase, +- dev->length, +- LOCOMO_DRIVER_NAME(dev))) { +- err = -EBUSY; +- printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n"); +- goto err_free_mem; +- } ++ locomokbd->regmap = dev_get_regmap(dev->dev.parent, NULL); ++ if (!locomokbd->regmap) ++ return -EINVAL; + +- locomo_set_drvdata(dev, locomokbd); ++ locomokbd->irq = platform_get_irq(dev, 0); ++ if (locomokbd->irq < 0) ++ return -ENXIO; + +- locomokbd->base = (unsigned long) dev->mapbase; ++ platform_set_drvdata(dev, locomokbd); + + spin_lock_init(&locomokbd->lock); + +@@ -270,11 +252,13 @@ static int locomokbd_probe(struct locomo_dev *dev) + + locomokbd->suspend_jiffies = jiffies; + +- locomokbd->input = input_dev; +- strcpy(locomokbd->phys, "locomokbd/input0"); ++ input_dev = input_allocate_device(); ++ if (!input_dev) ++ return -ENOMEM; + ++ locomokbd->input = input_dev; + input_dev->name = "LoCoMo keyboard"; +- input_dev->phys = locomokbd->phys; ++ input_dev->phys = "locomokbd/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; +@@ -291,16 +275,30 @@ static int locomokbd_probe(struct locomo_dev *dev) + + input_set_drvdata(input_dev, locomokbd); + +- memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode)); ++ memcpy(locomokbd->keycode, ++ locomokbd_keycode, ++ sizeof(locomokbd->keycode)); ++ ++ if (machine_is_collie()) ++ locomokbd->keycode[18] = KEY_HOME; ++ else ++ locomokbd->keycode[3] = KEY_HOME; ++ + for (i = 0; i < LOCOMOKBD_NUMKEYS; i++) +- set_bit(locomokbd->keycode[i], input_dev->keybit); +- clear_bit(0, input_dev->keybit); ++ input_set_capability(input_dev, EV_KEY, locomokbd->keycode[i]); ++ input_set_capability(input_dev, EV_PWR, KEY_SUSPEND); ++ __set_bit(EV_REP, input_dev->evbit); ++ ++ regmap_write(locomokbd->regmap, LOCOMO_KCMD, 1); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, 0x0); ++ regmap_write(locomokbd->regmap, LOCOMO_KIC, 0x0); + + /* attempt to get the interrupt */ +- err = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd); ++ err = request_irq(locomokbd->irq, locomokbd_interrupt, 0, ++ "locomokbd", locomokbd); + if (err) { +- printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n"); +- goto err_release_region; ++ dev_err(&dev->dev, "locomokbd: Can't get irq for keyboard\n"); ++ goto err_free_mem; + } + + err = input_register_device(locomokbd->input); +@@ -309,54 +307,71 @@ static int locomokbd_probe(struct locomo_dev *dev) + + return 0; + +- err_free_irq: +- free_irq(dev->irq[0], locomokbd); +- err_release_region: +- release_mem_region((unsigned long) dev->mapbase, dev->length); +- locomo_set_drvdata(dev, NULL); +- err_free_mem: ++err_free_irq: ++ free_irq(locomokbd->irq, locomokbd); ++err_free_mem: + input_free_device(input_dev); +- kfree(locomokbd); + + return err; + } + +-static int locomokbd_remove(struct locomo_dev *dev) ++static int locomokbd_remove(struct platform_device *dev) + { +- struct locomokbd *locomokbd = locomo_get_drvdata(dev); ++ struct locomokbd *locomokbd = platform_get_drvdata(dev); + +- free_irq(dev->irq[0], locomokbd); ++ free_irq(locomokbd->irq, locomokbd); + + del_timer_sync(&locomokbd->timer); + + input_unregister_device(locomokbd->input); +- locomo_set_drvdata(dev, NULL); + +- release_mem_region((unsigned long) dev->mapbase, dev->length); ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int locomokbd_suspend(struct device *dev) ++{ ++ struct locomokbd *locomokbd = dev_get_drvdata(dev); ++ ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x0); + +- kfree(locomokbd); ++ del_timer_sync(&locomokbd->timer); + + return 0; + } + +-static struct locomo_driver keyboard_driver = { +- .drv = { +- .name = "locomokbd" ++static int locomokbd_resume(struct device *dev) ++{ ++ struct locomokbd *locomokbd = dev_get_drvdata(dev); ++ ++ regmap_write(locomokbd->regmap, LOCOMO_KCMD, 1); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, 0); ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x100, 0); ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10); ++ ++ locomokbd_scankeyboard(locomokbd); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(locomo_kbd_pm, locomokbd_suspend, locomokbd_resume); ++#define LOCOMO_KBD_PM (&locomo_kbd_pm) ++#else ++#define LOCOMO_KBD_PM NULL ++#endif ++ ++static struct platform_driver locomokbd_driver = { ++ .driver = { ++ .name = "locomo-kbd", ++ .pm = LOCOMO_KBD_PM, + }, +- .devid = LOCOMO_DEVID_KEYBOARD, + .probe = locomokbd_probe, + .remove = locomokbd_remove, + }; + +-static int __init locomokbd_init(void) +-{ +- return locomo_driver_register(&keyboard_driver); +-} +- +-static void __exit locomokbd_exit(void) +-{ +- locomo_driver_unregister(&keyboard_driver); +-} ++module_platform_driver(locomokbd_driver); + +-module_init(locomokbd_init); +-module_exit(locomokbd_exit); ++MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); ++MODULE_DESCRIPTION("LoCoMo keyboard driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:locomo-kbd"); +-- +1.9.1 + |