1 /* 2 * OMAP4 Keypad Driver 3 * 4 * Copyright (C) 2010 Texas Instruments 5 * 6 * Author: Abraham Arce <x0066660@ti.com> 7 * Initial Code: Syed Rafiuddin <rafiuddin.syed@ti.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24 #include <linux/module.h> 25 #include <linux/init.h> 26 #include <linux/interrupt.h> 27 #include <linux/platform_device.h> 28 #include <linux/errno.h> 29 #include <linux/io.h> 30 #include <linux/input.h> 31 #include <linux/slab.h> 32 #include <linux/pm_runtime.h> 33 34 #include <plat/omap4-keypad.h> 35 36 /* OMAP4 registers */ 37 #define OMAP4_KBD_REVISION 0x00 38 #define OMAP4_KBD_SYSCONFIG 0x10 39 #define OMAP4_KBD_SYSSTATUS 0x14 40 #define OMAP4_KBD_IRQSTATUS 0x18 41 #define OMAP4_KBD_IRQENABLE 0x1C 42 #define OMAP4_KBD_WAKEUPENABLE 0x20 43 #define OMAP4_KBD_PENDING 0x24 44 #define OMAP4_KBD_CTRL 0x28 45 #define OMAP4_KBD_DEBOUNCINGTIME 0x2C 46 #define OMAP4_KBD_LONGKEYTIME 0x30 47 #define OMAP4_KBD_TIMEOUT 0x34 48 #define OMAP4_KBD_STATEMACHINE 0x38 49 #define OMAP4_KBD_ROWINPUTS 0x3C 50 #define OMAP4_KBD_COLUMNOUTPUTS 0x40 51 #define OMAP4_KBD_FULLCODE31_0 0x44 52 #define OMAP4_KBD_FULLCODE63_32 0x48 53 54 /* OMAP4 bit definitions */ 55 #define OMAP4_DEF_IRQENABLE_EVENTEN (1 << 0) 56 #define OMAP4_DEF_IRQENABLE_LONGKEY (1 << 1) 57 #define OMAP4_DEF_IRQENABLE_TIMEOUTEN (1 << 2) 58 #define OMAP4_DEF_WUP_EVENT_ENA (1 << 0) 59 #define OMAP4_DEF_WUP_LONG_KEY_ENA (1 << 1) 60 #define OMAP4_DEF_CTRL_NOSOFTMODE (1 << 1) 61 #define OMAP4_DEF_CTRLPTVVALUE (1 << 2) 62 #define OMAP4_DEF_CTRLPTV (1 << 1) 63 64 /* OMAP4 values */ 65 #define OMAP4_VAL_IRQDISABLE 0x00 66 #define OMAP4_VAL_DEBOUNCINGTIME 0x07 67 #define OMAP4_VAL_FUNCTIONALCFG 0x1E 68 69 #define OMAP4_MASK_IRQSTATUSDISABLE 0xFFFF 70 71 struct omap4_keypad { 72 struct input_dev *input; 73 74 void __iomem *base; 75 int irq; 76 77 unsigned int rows; 78 unsigned int cols; 79 unsigned int row_shift; 80 unsigned char key_state[8]; 81 unsigned short keymap[]; 82 }; 83 84 /* Interrupt handler */ 85 static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) 86 { 87 struct omap4_keypad *keypad_data = dev_id; 88 struct input_dev *input_dev = keypad_data->input; 89 unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)]; 90 unsigned int col, row, code, changed; 91 u32 *new_state = (u32 *) key_state; 92 93 /* Disable interrupts */ 94 __raw_writel(OMAP4_VAL_IRQDISABLE, 95 keypad_data->base + OMAP4_KBD_IRQENABLE); 96 97 *new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0); 98 *(new_state + 1) = __raw_readl(keypad_data->base 99 + OMAP4_KBD_FULLCODE63_32); 100 101 for (row = 0; row < keypad_data->rows; row++) { 102 changed = key_state[row] ^ keypad_data->key_state[row]; 103 if (!changed) 104 continue; 105 106 for (col = 0; col < keypad_data->cols; col++) { 107 if (changed & (1 << col)) { 108 code = MATRIX_SCAN_CODE(row, col, 109 keypad_data->row_shift); 110 input_event(input_dev, EV_MSC, MSC_SCAN, code); 111 input_report_key(input_dev, 112 keypad_data->keymap[code], 113 key_state[row] & (1 << col)); 114 } 115 } 116 } 117 118 input_sync(input_dev); 119 120 memcpy(keypad_data->key_state, key_state, 121 sizeof(keypad_data->key_state)); 122 123 /* clear pending interrupts */ 124 __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS), 125 keypad_data->base + OMAP4_KBD_IRQSTATUS); 126 127 /* enable interrupts */ 128 __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, 129 keypad_data->base + OMAP4_KBD_IRQENABLE); 130 131 return IRQ_HANDLED; 132 } 133 134 static int omap4_keypad_open(struct input_dev *input) 135 { 136 struct omap4_keypad *keypad_data = input_get_drvdata(input); 137 138 pm_runtime_get_sync(input->dev.parent); 139 140 disable_irq(keypad_data->irq); 141 142 __raw_writel(OMAP4_VAL_FUNCTIONALCFG, 143 keypad_data->base + OMAP4_KBD_CTRL); 144 __raw_writel(OMAP4_VAL_DEBOUNCINGTIME, 145 keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME); 146 __raw_writel(OMAP4_VAL_IRQDISABLE, 147 keypad_data->base + OMAP4_KBD_IRQSTATUS); 148 __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, 149 keypad_data->base + OMAP4_KBD_IRQENABLE); 150 __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA, 151 keypad_data->base + OMAP4_KBD_WAKEUPENABLE); 152 153 enable_irq(keypad_data->irq); 154 155 return 0; 156 } 157 158 static void omap4_keypad_close(struct input_dev *input) 159 { 160 struct omap4_keypad *keypad_data = input_get_drvdata(input); 161 162 disable_irq(keypad_data->irq); 163 164 /* Disable interrupts */ 165 __raw_writel(OMAP4_VAL_IRQDISABLE, 166 keypad_data->base + OMAP4_KBD_IRQENABLE); 167 168 /* clear pending interrupts */ 169 __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS), 170 keypad_data->base + OMAP4_KBD_IRQSTATUS); 171 172 enable_irq(keypad_data->irq); 173 174 pm_runtime_put_sync(input->dev.parent); 175 } 176 177 static int __devinit omap4_keypad_probe(struct platform_device *pdev) 178 { 179 const struct omap4_keypad_platform_data *pdata; 180 struct omap4_keypad *keypad_data; 181 struct input_dev *input_dev; 182 struct resource *res; 183 resource_size_t size; 184 unsigned int row_shift, max_keys; 185 int irq; 186 int error; 187 188 /* platform data */ 189 pdata = pdev->dev.platform_data; 190 if (!pdata) { 191 dev_err(&pdev->dev, "no platform data defined\n"); 192 return -EINVAL; 193 } 194 195 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 196 if (!res) { 197 dev_err(&pdev->dev, "no base address specified\n"); 198 return -EINVAL; 199 } 200 201 irq = platform_get_irq(pdev, 0); 202 if (!irq) { 203 dev_err(&pdev->dev, "no keyboard irq assigned\n"); 204 return -EINVAL; 205 } 206 207 if (!pdata->keymap_data) { 208 dev_err(&pdev->dev, "no keymap data defined\n"); 209 return -EINVAL; 210 } 211 212 row_shift = get_count_order(pdata->cols); 213 max_keys = pdata->rows << row_shift; 214 215 keypad_data = kzalloc(sizeof(struct omap4_keypad) + 216 max_keys * sizeof(keypad_data->keymap[0]), 217 GFP_KERNEL); 218 if (!keypad_data) { 219 dev_err(&pdev->dev, "keypad_data memory allocation failed\n"); 220 return -ENOMEM; 221 } 222 223 size = resource_size(res); 224 225 res = request_mem_region(res->start, size, pdev->name); 226 if (!res) { 227 dev_err(&pdev->dev, "can't request mem region\n"); 228 error = -EBUSY; 229 goto err_free_keypad; 230 } 231 232 keypad_data->base = ioremap(res->start, resource_size(res)); 233 if (!keypad_data->base) { 234 dev_err(&pdev->dev, "can't ioremap mem resource\n"); 235 error = -ENOMEM; 236 goto err_release_mem; 237 } 238 239 keypad_data->irq = irq; 240 keypad_data->row_shift = row_shift; 241 keypad_data->rows = pdata->rows; 242 keypad_data->cols = pdata->cols; 243 244 /* input device allocation */ 245 keypad_data->input = input_dev = input_allocate_device(); 246 if (!input_dev) { 247 error = -ENOMEM; 248 goto err_unmap; 249 } 250 251 input_dev->name = pdev->name; 252 input_dev->dev.parent = &pdev->dev; 253 input_dev->id.bustype = BUS_HOST; 254 input_dev->id.vendor = 0x0001; 255 input_dev->id.product = 0x0001; 256 input_dev->id.version = 0x0001; 257 258 input_dev->open = omap4_keypad_open; 259 input_dev->close = omap4_keypad_close; 260 261 input_dev->keycode = keypad_data->keymap; 262 input_dev->keycodesize = sizeof(keypad_data->keymap[0]); 263 input_dev->keycodemax = max_keys; 264 265 __set_bit(EV_KEY, input_dev->evbit); 266 __set_bit(EV_REP, input_dev->evbit); 267 268 input_set_capability(input_dev, EV_MSC, MSC_SCAN); 269 270 input_set_drvdata(input_dev, keypad_data); 271 272 matrix_keypad_build_keymap(pdata->keymap_data, row_shift, 273 input_dev->keycode, input_dev->keybit); 274 275 error = request_irq(keypad_data->irq, omap4_keypad_interrupt, 276 IRQF_TRIGGER_RISING, 277 "omap4-keypad", keypad_data); 278 if (error) { 279 dev_err(&pdev->dev, "failed to register interrupt\n"); 280 goto err_free_input; 281 } 282 283 pm_runtime_enable(&pdev->dev); 284 285 error = input_register_device(keypad_data->input); 286 if (error < 0) { 287 dev_err(&pdev->dev, "failed to register input device\n"); 288 goto err_pm_disable; 289 } 290 291 platform_set_drvdata(pdev, keypad_data); 292 return 0; 293 294 err_pm_disable: 295 pm_runtime_disable(&pdev->dev); 296 free_irq(keypad_data->irq, keypad_data); 297 err_free_input: 298 input_free_device(input_dev); 299 err_unmap: 300 iounmap(keypad_data->base); 301 err_release_mem: 302 release_mem_region(res->start, size); 303 err_free_keypad: 304 kfree(keypad_data); 305 return error; 306 } 307 308 static int __devexit omap4_keypad_remove(struct platform_device *pdev) 309 { 310 struct omap4_keypad *keypad_data = platform_get_drvdata(pdev); 311 struct resource *res; 312 313 free_irq(keypad_data->irq, keypad_data); 314 315 pm_runtime_disable(&pdev->dev); 316 317 input_unregister_device(keypad_data->input); 318 319 iounmap(keypad_data->base); 320 321 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 322 release_mem_region(res->start, resource_size(res)); 323 324 kfree(keypad_data); 325 platform_set_drvdata(pdev, NULL); 326 327 return 0; 328 } 329 330 static struct platform_driver omap4_keypad_driver = { 331 .probe = omap4_keypad_probe, 332 .remove = __devexit_p(omap4_keypad_remove), 333 .driver = { 334 .name = "omap4-keypad", 335 .owner = THIS_MODULE, 336 }, 337 }; 338 339 static int __init omap4_keypad_init(void) 340 { 341 return platform_driver_register(&omap4_keypad_driver); 342 } 343 module_init(omap4_keypad_init); 344 345 static void __exit omap4_keypad_exit(void) 346 { 347 platform_driver_unregister(&omap4_keypad_driver); 348 } 349 module_exit(omap4_keypad_exit); 350 351 MODULE_AUTHOR("Texas Instruments"); 352 MODULE_DESCRIPTION("OMAP4 Keypad Driver"); 353 MODULE_LICENSE("GPL"); 354 MODULE_ALIAS("platform:omap4-keypad"); 355