Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add support for keyboards on ST SPEAr platform

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Rajeev Kumar and committed by
Dmitry Torokhov
bc95df78 c44f2420

+495
+141
arch/arm/plat-spear/include/plat/keyboard.h
··· 1 + /* 2 + * Copyright (C) 2010 ST Microelectronics 3 + * Rajeev Kumar<rajeev-dlh.kumar@st.com> 4 + * 5 + * This file is licensed under the terms of the GNU General Public 6 + * License version 2. This program is licensed "as is" without any 7 + * warranty of any kind, whether express or implied. 8 + */ 9 + 10 + #ifndef __PLAT_KEYBOARD_H 11 + #define __PLAT_KEYBOARD_H 12 + 13 + #include <linux/bitops.h> 14 + #include <linux/input.h> 15 + #include <linux/input/matrix_keypad.h> 16 + #include <linux/types.h> 17 + 18 + #define DECLARE_KEYMAP(_name) \ 19 + int _name[] = { \ 20 + KEY(0, 0, KEY_ESC), \ 21 + KEY(0, 1, KEY_1), \ 22 + KEY(0, 2, KEY_2), \ 23 + KEY(0, 3, KEY_3), \ 24 + KEY(0, 4, KEY_4), \ 25 + KEY(0, 5, KEY_5), \ 26 + KEY(0, 6, KEY_6), \ 27 + KEY(0, 7, KEY_7), \ 28 + KEY(0, 8, KEY_8), \ 29 + KEY(1, 0, KEY_9), \ 30 + KEY(1, 1, KEY_MINUS), \ 31 + KEY(1, 2, KEY_EQUAL), \ 32 + KEY(1, 3, KEY_BACKSPACE), \ 33 + KEY(1, 4, KEY_TAB), \ 34 + KEY(1, 5, KEY_Q), \ 35 + KEY(1, 6, KEY_W), \ 36 + KEY(1, 7, KEY_E), \ 37 + KEY(1, 8, KEY_R), \ 38 + KEY(2, 0, KEY_T), \ 39 + KEY(2, 1, KEY_Y), \ 40 + KEY(2, 2, KEY_U), \ 41 + KEY(2, 3, KEY_I), \ 42 + KEY(2, 4, KEY_O), \ 43 + KEY(2, 5, KEY_P), \ 44 + KEY(2, 6, KEY_LEFTBRACE), \ 45 + KEY(2, 7, KEY_RIGHTBRACE), \ 46 + KEY(2, 8, KEY_ENTER), \ 47 + KEY(3, 0, KEY_LEFTCTRL), \ 48 + KEY(3, 1, KEY_A), \ 49 + KEY(3, 2, KEY_S), \ 50 + KEY(3, 3, KEY_D), \ 51 + KEY(3, 4, KEY_F), \ 52 + KEY(3, 5, KEY_G), \ 53 + KEY(3, 6, KEY_H), \ 54 + KEY(3, 7, KEY_J), \ 55 + KEY(3, 8, KEY_K), \ 56 + KEY(4, 0, KEY_L), \ 57 + KEY(4, 1, KEY_SEMICOLON), \ 58 + KEY(4, 2, KEY_APOSTROPHE), \ 59 + KEY(4, 3, KEY_GRAVE), \ 60 + KEY(4, 4, KEY_LEFTSHIFT), \ 61 + KEY(4, 5, KEY_BACKSLASH), \ 62 + KEY(4, 6, KEY_Z), \ 63 + KEY(4, 7, KEY_X), \ 64 + KEY(4, 8, KEY_C), \ 65 + KEY(4, 0, KEY_L), \ 66 + KEY(4, 1, KEY_SEMICOLON), \ 67 + KEY(4, 2, KEY_APOSTROPHE), \ 68 + KEY(4, 3, KEY_GRAVE), \ 69 + KEY(4, 4, KEY_LEFTSHIFT), \ 70 + KEY(4, 5, KEY_BACKSLASH), \ 71 + KEY(4, 6, KEY_Z), \ 72 + KEY(4, 7, KEY_X), \ 73 + KEY(4, 8, KEY_C), \ 74 + KEY(4, 0, KEY_L), \ 75 + KEY(4, 1, KEY_SEMICOLON), \ 76 + KEY(4, 2, KEY_APOSTROPHE), \ 77 + KEY(4, 3, KEY_GRAVE), \ 78 + KEY(4, 4, KEY_LEFTSHIFT), \ 79 + KEY(4, 5, KEY_BACKSLASH), \ 80 + KEY(4, 6, KEY_Z), \ 81 + KEY(4, 7, KEY_X), \ 82 + KEY(4, 8, KEY_C), \ 83 + KEY(5, 0, KEY_V), \ 84 + KEY(5, 1, KEY_B), \ 85 + KEY(5, 2, KEY_N), \ 86 + KEY(5, 3, KEY_M), \ 87 + KEY(5, 4, KEY_COMMA), \ 88 + KEY(5, 5, KEY_DOT), \ 89 + KEY(5, 6, KEY_SLASH), \ 90 + KEY(5, 7, KEY_RIGHTSHIFT), \ 91 + KEY(5, 8, KEY_KPASTERISK), \ 92 + KEY(6, 0, KEY_LEFTALT), \ 93 + KEY(6, 1, KEY_SPACE), \ 94 + KEY(6, 2, KEY_CAPSLOCK), \ 95 + KEY(6, 3, KEY_F1), \ 96 + KEY(6, 4, KEY_F2), \ 97 + KEY(6, 5, KEY_F3), \ 98 + KEY(6, 6, KEY_F4), \ 99 + KEY(6, 7, KEY_F5), \ 100 + KEY(6, 8, KEY_F6), \ 101 + KEY(7, 0, KEY_F7), \ 102 + KEY(7, 1, KEY_F8), \ 103 + KEY(7, 2, KEY_F9), \ 104 + KEY(7, 3, KEY_F10), \ 105 + KEY(7, 4, KEY_NUMLOCK), \ 106 + KEY(7, 5, KEY_SCROLLLOCK), \ 107 + KEY(7, 6, KEY_KP7), \ 108 + KEY(7, 7, KEY_KP8), \ 109 + KEY(7, 8, KEY_KP9), \ 110 + KEY(8, 0, KEY_KPMINUS), \ 111 + KEY(8, 1, KEY_KP4), \ 112 + KEY(8, 2, KEY_KP5), \ 113 + KEY(8, 3, KEY_KP6), \ 114 + KEY(8, 4, KEY_KPPLUS), \ 115 + KEY(8, 5, KEY_KP1), \ 116 + KEY(8, 6, KEY_KP2), \ 117 + KEY(8, 7, KEY_KP3), \ 118 + KEY(8, 8, KEY_KP0), \ 119 + } 120 + 121 + /** 122 + * struct kbd_platform_data - spear keyboard platform data 123 + * keymap: pointer to keymap data (table and size) 124 + * rep: enables key autorepeat 125 + * 126 + * This structure is supposed to be used by platform code to supply 127 + * keymaps to drivers that implement keyboards. 128 + */ 129 + struct kbd_platform_data { 130 + const struct matrix_keymap_data *keymap; 131 + bool rep; 132 + }; 133 + 134 + /* This function is used to set platform data field of pdev->dev */ 135 + static inline void 136 + kbd_set_plat_data(struct platform_device *pdev, struct kbd_platform_data *data) 137 + { 138 + pdev->dev.platform_data = data; 139 + } 140 + 141 + #endif /* __PLAT_KEYBOARD_H */
+9
drivers/input/keyboard/Kconfig
··· 443 443 To compile this driver as a module, choose M here: the 444 444 module will be called omap4-keypad. 445 445 446 + config KEYBOARD_SPEAR 447 + tristate "ST SPEAR keyboard support" 448 + depends on PLAT_SPEAR 449 + help 450 + Say Y here if you want to use the SPEAR keyboard. 451 + 452 + To compile this driver as a module, choose M here: the 453 + module will be called spear-keboard. 454 + 446 455 config KEYBOARD_TNETV107X 447 456 tristate "TI TNETV107X keypad support" 448 457 depends on ARCH_DAVINCI_TNETV107X
+1
drivers/input/keyboard/Makefile
··· 37 37 obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o 38 38 obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o 39 39 obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o 40 + obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o 40 41 obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o 41 42 obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o 42 43 obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
+344
drivers/input/keyboard/spear-keyboard.c
··· 1 + /* 2 + * SPEAr Keyboard Driver 3 + * Based on omap-keypad driver 4 + * 5 + * Copyright (C) 2010 ST Microelectronics 6 + * Rajeev Kumar<rajeev-dlh.kumar@st.com> 7 + * 8 + * This file is licensed under the terms of the GNU General Public 9 + * License version 2. This program is licensed "as is" without any 10 + * warranty of any kind, whether express or implied. 11 + */ 12 + 13 + #include <linux/clk.h> 14 + #include <linux/errno.h> 15 + #include <linux/init.h> 16 + #include <linux/interrupt.h> 17 + #include <linux/input.h> 18 + #include <linux/io.h> 19 + #include <linux/irq.h> 20 + #include <linux/kernel.h> 21 + #include <linux/module.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/pm_wakeup.h> 24 + #include <linux/slab.h> 25 + #include <linux/types.h> 26 + #include <plat/keyboard.h> 27 + 28 + /* Keyboard Registers */ 29 + #define MODE_REG 0x00 /* 16 bit reg */ 30 + #define STATUS_REG 0x0C /* 2 bit reg */ 31 + #define DATA_REG 0x10 /* 8 bit reg */ 32 + #define INTR_MASK 0x54 33 + 34 + /* Register Values */ 35 + /* 36 + * pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode 37 + * control register as 1010010(82MHZ) 38 + */ 39 + #define PCLK_FREQ_MSK 0xA400 /* 82 MHz */ 40 + #define START_SCAN 0x0100 41 + #define SCAN_RATE_10 0x0000 42 + #define SCAN_RATE_20 0x0004 43 + #define SCAN_RATE_40 0x0008 44 + #define SCAN_RATE_80 0x000C 45 + #define MODE_KEYBOARD 0x0002 46 + #define DATA_AVAIL 0x2 47 + 48 + #define KEY_MASK 0xFF000000 49 + #define KEY_VALUE 0x00FFFFFF 50 + #define ROW_MASK 0xF0 51 + #define COLUMN_MASK 0x0F 52 + #define ROW_SHIFT 4 53 + 54 + struct spear_kbd { 55 + struct input_dev *input; 56 + struct resource *res; 57 + void __iomem *io_base; 58 + struct clk *clk; 59 + unsigned int irq; 60 + unsigned short last_key; 61 + unsigned short keycodes[256]; 62 + }; 63 + 64 + static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) 65 + { 66 + struct spear_kbd *kbd = dev_id; 67 + struct input_dev *input = kbd->input; 68 + unsigned int key; 69 + u8 sts, val; 70 + 71 + sts = readb(kbd->io_base + STATUS_REG); 72 + if (sts & DATA_AVAIL) 73 + return IRQ_NONE; 74 + 75 + if (kbd->last_key != KEY_RESERVED) { 76 + input_report_key(input, kbd->last_key, 0); 77 + kbd->last_key = KEY_RESERVED; 78 + } 79 + 80 + /* following reads active (row, col) pair */ 81 + val = readb(kbd->io_base + DATA_REG); 82 + key = kbd->keycodes[val]; 83 + 84 + input_event(input, EV_MSC, MSC_SCAN, val); 85 + input_report_key(input, key, 1); 86 + input_sync(input); 87 + 88 + kbd->last_key = key; 89 + 90 + /* clear interrupt */ 91 + writeb(0, kbd->io_base + STATUS_REG); 92 + 93 + return IRQ_HANDLED; 94 + } 95 + 96 + static int spear_kbd_open(struct input_dev *dev) 97 + { 98 + struct spear_kbd *kbd = input_get_drvdata(dev); 99 + int error; 100 + u16 val; 101 + 102 + kbd->last_key = KEY_RESERVED; 103 + 104 + error = clk_enable(kbd->clk); 105 + if (error) 106 + return error; 107 + 108 + /* program keyboard */ 109 + val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK; 110 + writew(val, kbd->io_base + MODE_REG); 111 + writeb(1, kbd->io_base + STATUS_REG); 112 + 113 + /* start key scan */ 114 + val = readw(kbd->io_base + MODE_REG); 115 + val |= START_SCAN; 116 + writew(val, kbd->io_base + MODE_REG); 117 + 118 + return 0; 119 + } 120 + 121 + static void spear_kbd_close(struct input_dev *dev) 122 + { 123 + struct spear_kbd *kbd = input_get_drvdata(dev); 124 + u16 val; 125 + 126 + /* stop key scan */ 127 + val = readw(kbd->io_base + MODE_REG); 128 + val &= ~START_SCAN; 129 + writew(val, kbd->io_base + MODE_REG); 130 + 131 + clk_disable(kbd->clk); 132 + 133 + kbd->last_key = KEY_RESERVED; 134 + } 135 + 136 + static int __devinit spear_kbd_probe(struct platform_device *pdev) 137 + { 138 + const struct kbd_platform_data *pdata = pdev->dev.platform_data; 139 + const struct matrix_keymap_data *keymap; 140 + struct spear_kbd *kbd; 141 + struct input_dev *input_dev; 142 + struct resource *res; 143 + int irq; 144 + int error; 145 + 146 + if (!pdata) { 147 + dev_err(&pdev->dev, "Invalid platform data\n"); 148 + return -EINVAL; 149 + } 150 + 151 + keymap = pdata->keymap; 152 + if (!keymap) { 153 + dev_err(&pdev->dev, "no keymap defined\n"); 154 + return -EINVAL; 155 + } 156 + 157 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 158 + if (!res) { 159 + dev_err(&pdev->dev, "no keyboard resource defined\n"); 160 + return -EBUSY; 161 + } 162 + 163 + irq = platform_get_irq(pdev, 0); 164 + if (irq < 0) { 165 + dev_err(&pdev->dev, "not able to get irq for the device\n"); 166 + return irq; 167 + } 168 + 169 + kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); 170 + input_dev = input_allocate_device(); 171 + if (!kbd || !input_dev) { 172 + dev_err(&pdev->dev, "out of memory\n"); 173 + error = -ENOMEM; 174 + goto err_free_mem; 175 + } 176 + 177 + kbd->input = input_dev; 178 + kbd->irq = irq; 179 + kbd->res = request_mem_region(res->start, resource_size(res), 180 + pdev->name); 181 + if (!kbd->res) { 182 + dev_err(&pdev->dev, "keyboard region already claimed\n"); 183 + error = -EBUSY; 184 + goto err_free_mem; 185 + } 186 + 187 + kbd->io_base = ioremap(res->start, resource_size(res)); 188 + if (!kbd->io_base) { 189 + dev_err(&pdev->dev, "ioremap failed for kbd_region\n"); 190 + error = -ENOMEM; 191 + goto err_release_mem_region; 192 + } 193 + 194 + kbd->clk = clk_get(&pdev->dev, NULL); 195 + if (IS_ERR(kbd->clk)) { 196 + error = PTR_ERR(kbd->clk); 197 + goto err_iounmap; 198 + } 199 + 200 + input_dev->name = "Spear Keyboard"; 201 + input_dev->phys = "keyboard/input0"; 202 + input_dev->dev.parent = &pdev->dev; 203 + input_dev->id.bustype = BUS_HOST; 204 + input_dev->id.vendor = 0x0001; 205 + input_dev->id.product = 0x0001; 206 + input_dev->id.version = 0x0100; 207 + input_dev->open = spear_kbd_open; 208 + input_dev->close = spear_kbd_close; 209 + 210 + __set_bit(EV_KEY, input_dev->evbit); 211 + if (pdata->rep) 212 + __set_bit(EV_REP, input_dev->evbit); 213 + input_set_capability(input_dev, EV_MSC, MSC_SCAN); 214 + 215 + input_dev->keycode = kbd->keycodes; 216 + input_dev->keycodesize = sizeof(kbd->keycodes[0]); 217 + input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes); 218 + 219 + matrix_keypad_build_keymap(keymap, ROW_SHIFT, 220 + input_dev->keycode, input_dev->keybit); 221 + 222 + input_set_drvdata(input_dev, kbd); 223 + 224 + error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd); 225 + if (error) { 226 + dev_err(&pdev->dev, "request_irq fail\n"); 227 + goto err_put_clk; 228 + } 229 + 230 + error = input_register_device(input_dev); 231 + if (error) { 232 + dev_err(&pdev->dev, "Unable to register keyboard device\n"); 233 + goto err_free_irq; 234 + } 235 + 236 + device_init_wakeup(&pdev->dev, 1); 237 + platform_set_drvdata(pdev, kbd); 238 + 239 + return 0; 240 + 241 + err_free_irq: 242 + free_irq(kbd->irq, kbd); 243 + err_put_clk: 244 + clk_put(kbd->clk); 245 + err_iounmap: 246 + iounmap(kbd->io_base); 247 + err_release_mem_region: 248 + release_mem_region(res->start, resource_size(res)); 249 + err_free_mem: 250 + input_free_device(input_dev); 251 + kfree(kbd); 252 + 253 + return error; 254 + } 255 + 256 + static int __devexit spear_kbd_remove(struct platform_device *pdev) 257 + { 258 + struct spear_kbd *kbd = platform_get_drvdata(pdev); 259 + 260 + free_irq(kbd->irq, kbd); 261 + input_unregister_device(kbd->input); 262 + clk_put(kbd->clk); 263 + iounmap(kbd->io_base); 264 + release_mem_region(kbd->res->start, resource_size(kbd->res)); 265 + kfree(kbd); 266 + 267 + device_init_wakeup(&pdev->dev, 1); 268 + platform_set_drvdata(pdev, NULL); 269 + 270 + return 0; 271 + } 272 + 273 + #ifdef CONFIG_PM 274 + static int spear_kbd_suspend(struct device *dev) 275 + { 276 + struct platform_device *pdev = to_platform_device(dev); 277 + struct spear_kbd *kbd = platform_get_drvdata(pdev); 278 + struct input_dev *input_dev = kbd->input; 279 + 280 + mutex_lock(&input_dev->mutex); 281 + 282 + if (input_dev->users) 283 + clk_enable(kbd->clk); 284 + 285 + if (device_may_wakeup(&pdev->dev)) 286 + enable_irq_wake(kbd->irq); 287 + 288 + mutex_unlock(&input_dev->mutex); 289 + 290 + return 0; 291 + } 292 + 293 + static int spear_kbd_resume(struct device *dev) 294 + { 295 + struct platform_device *pdev = to_platform_device(dev); 296 + struct spear_kbd *kbd = platform_get_drvdata(pdev); 297 + struct input_dev *input_dev = kbd->input; 298 + 299 + mutex_lock(&input_dev->mutex); 300 + 301 + if (device_may_wakeup(&pdev->dev)) 302 + disable_irq_wake(kbd->irq); 303 + 304 + if (input_dev->users) 305 + clk_enable(kbd->clk); 306 + 307 + mutex_unlock(&input_dev->mutex); 308 + 309 + return 0; 310 + } 311 + 312 + static const struct dev_pm_ops spear_kbd_pm_ops = { 313 + .suspend = spear_kbd_suspend, 314 + .resume = spear_kbd_resume, 315 + }; 316 + #endif 317 + 318 + static struct platform_driver spear_kbd_driver = { 319 + .probe = spear_kbd_probe, 320 + .remove = __devexit_p(spear_kbd_remove), 321 + .driver = { 322 + .name = "keyboard", 323 + .owner = THIS_MODULE, 324 + #ifdef CONFIG_PM 325 + .pm = &spear_kbd_pm_ops, 326 + #endif 327 + }, 328 + }; 329 + 330 + static int __init spear_kbd_init(void) 331 + { 332 + return platform_driver_register(&spear_kbd_driver); 333 + } 334 + module_init(spear_kbd_init); 335 + 336 + static void __exit spear_kbd_exit(void) 337 + { 338 + platform_driver_unregister(&spear_kbd_driver); 339 + } 340 + module_exit(spear_kbd_exit); 341 + 342 + MODULE_AUTHOR("Rajeev Kumar"); 343 + MODULE_DESCRIPTION("SPEAr Keyboard Driver"); 344 + MODULE_LICENSE("GPL");