1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * linux/drivers/input/keyboard/omap-keypad.c 4 * 5 * OMAP Keypad Driver 6 * 7 * Copyright (C) 2003 Nokia Corporation 8 * Written by Timo Teräs <ext-timo.teras@nokia.com> 9 * 10 * Added support for H2 & H3 Keypad 11 * Copyright (C) 2004 Texas Instruments 12 */ 13 14 #include <linux/module.h> 15 #include <linux/interrupt.h> 16 #include <linux/types.h> 17 #include <linux/input.h> 18 #include <linux/kernel.h> 19 #include <linux/delay.h> 20 #include <linux/platform_device.h> 21 #include <linux/mutex.h> 22 #include <linux/errno.h> 23 #include <linux/slab.h> 24 #include <linux/gpio.h> 25 #include <linux/platform_data/gpio-omap.h> 26 #include <linux/platform_data/keypad-omap.h> 27 #include <linux/soc/ti/omap1-io.h> 28 29 #undef NEW_BOARD_LEARNING_MODE 30 31 static void omap_kp_tasklet(unsigned long); 32 static void omap_kp_timer(struct timer_list *); 33 34 static unsigned char keypad_state[8]; 35 static DEFINE_MUTEX(kp_enable_mutex); 36 static int kp_enable = 1; 37 static int kp_cur_group = -1; 38 39 struct omap_kp { 40 struct input_dev *input; 41 struct timer_list timer; 42 int irq; 43 unsigned int rows; 44 unsigned int cols; 45 unsigned long delay; 46 unsigned int debounce; 47 unsigned short keymap[]; 48 }; 49 50 static DECLARE_TASKLET_DISABLED_OLD(kp_tasklet, omap_kp_tasklet); 51 52 static unsigned int *row_gpios; 53 static unsigned int *col_gpios; 54 55 static irqreturn_t omap_kp_interrupt(int irq, void *dev_id) 56 { 57 /* disable keyboard interrupt and schedule for handling */ 58 omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 59 60 tasklet_schedule(&kp_tasklet); 61 62 return IRQ_HANDLED; 63 } 64 65 static void omap_kp_timer(struct timer_list *unused) 66 { 67 tasklet_schedule(&kp_tasklet); 68 } 69 70 static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state) 71 { 72 int col = 0; 73 74 /* disable keyboard interrupt and schedule for handling */ 75 omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 76 77 /* read the keypad status */ 78 omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); 79 for (col = 0; col < omap_kp->cols; col++) { 80 omap_writew(~(1 << col) & 0xff, 81 OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); 82 83 udelay(omap_kp->delay); 84 85 state[col] = ~omap_readw(OMAP1_MPUIO_BASE + 86 OMAP_MPUIO_KBR_LATCH) & 0xff; 87 } 88 omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); 89 udelay(2); 90 } 91 92 static void omap_kp_tasklet(unsigned long data) 93 { 94 struct omap_kp *omap_kp_data = (struct omap_kp *) data; 95 unsigned short *keycodes = omap_kp_data->input->keycode; 96 unsigned int row_shift = get_count_order(omap_kp_data->cols); 97 unsigned char new_state[8], changed, key_down = 0; 98 int col, row; 99 100 /* check for any changes */ 101 omap_kp_scan_keypad(omap_kp_data, new_state); 102 103 /* check for changes and print those */ 104 for (col = 0; col < omap_kp_data->cols; col++) { 105 changed = new_state[col] ^ keypad_state[col]; 106 key_down |= new_state[col]; 107 if (changed == 0) 108 continue; 109 110 for (row = 0; row < omap_kp_data->rows; row++) { 111 int key; 112 if (!(changed & (1 << row))) 113 continue; 114 #ifdef NEW_BOARD_LEARNING_MODE 115 printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col, 116 row, (new_state[col] & (1 << row)) ? 117 "pressed" : "released"); 118 #else 119 key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)]; 120 121 if (!(kp_cur_group == (key & GROUP_MASK) || 122 kp_cur_group == -1)) 123 continue; 124 125 kp_cur_group = key & GROUP_MASK; 126 input_report_key(omap_kp_data->input, key & ~GROUP_MASK, 127 new_state[col] & (1 << row)); 128 #endif 129 } 130 } 131 input_sync(omap_kp_data->input); 132 memcpy(keypad_state, new_state, sizeof(keypad_state)); 133 134 if (key_down) { 135 /* some key is pressed - keep irq disabled and use timer 136 * to poll the keypad */ 137 mod_timer(&omap_kp_data->timer, jiffies + HZ / 20); 138 } else { 139 /* enable interrupts */ 140 omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 141 kp_cur_group = -1; 142 } 143 } 144 145 static ssize_t omap_kp_enable_show(struct device *dev, 146 struct device_attribute *attr, char *buf) 147 { 148 return sprintf(buf, "%u\n", kp_enable); 149 } 150 151 static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr, 152 const char *buf, size_t count) 153 { 154 struct omap_kp *omap_kp = dev_get_drvdata(dev); 155 int state; 156 157 if (sscanf(buf, "%u", &state) != 1) 158 return -EINVAL; 159 160 if ((state != 1) && (state != 0)) 161 return -EINVAL; 162 163 mutex_lock(&kp_enable_mutex); 164 if (state != kp_enable) { 165 if (state) 166 enable_irq(omap_kp->irq); 167 else 168 disable_irq(omap_kp->irq); 169 kp_enable = state; 170 } 171 mutex_unlock(&kp_enable_mutex); 172 173 return strnlen(buf, count); 174 } 175 176 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store); 177 178 static int omap_kp_probe(struct platform_device *pdev) 179 { 180 struct omap_kp *omap_kp; 181 struct input_dev *input_dev; 182 struct omap_kp_platform_data *pdata = dev_get_platdata(&pdev->dev); 183 int i, col_idx, row_idx, ret; 184 unsigned int row_shift, keycodemax; 185 186 if (!pdata->rows || !pdata->cols || !pdata->keymap_data) { 187 printk(KERN_ERR "No rows, cols or keymap_data from pdata\n"); 188 return -EINVAL; 189 } 190 191 row_shift = get_count_order(pdata->cols); 192 keycodemax = pdata->rows << row_shift; 193 194 omap_kp = kzalloc(struct_size(omap_kp, keymap, keycodemax), GFP_KERNEL); 195 input_dev = input_allocate_device(); 196 if (!omap_kp || !input_dev) { 197 kfree(omap_kp); 198 input_free_device(input_dev); 199 return -ENOMEM; 200 } 201 202 platform_set_drvdata(pdev, omap_kp); 203 204 omap_kp->input = input_dev; 205 206 /* Disable the interrupt for the MPUIO keyboard */ 207 omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 208 209 if (pdata->delay) 210 omap_kp->delay = pdata->delay; 211 212 if (pdata->row_gpios && pdata->col_gpios) { 213 row_gpios = pdata->row_gpios; 214 col_gpios = pdata->col_gpios; 215 } 216 217 omap_kp->rows = pdata->rows; 218 omap_kp->cols = pdata->cols; 219 220 col_idx = 0; 221 row_idx = 0; 222 223 timer_setup(&omap_kp->timer, omap_kp_timer, 0); 224 225 /* get the irq and init timer*/ 226 kp_tasklet.data = (unsigned long) omap_kp; 227 tasklet_enable(&kp_tasklet); 228 229 ret = device_create_file(&pdev->dev, &dev_attr_enable); 230 if (ret < 0) 231 goto err2; 232 233 /* setup input device */ 234 input_dev->name = "omap-keypad"; 235 input_dev->phys = "omap-keypad/input0"; 236 input_dev->dev.parent = &pdev->dev; 237 238 input_dev->id.bustype = BUS_HOST; 239 input_dev->id.vendor = 0x0001; 240 input_dev->id.product = 0x0001; 241 input_dev->id.version = 0x0100; 242 243 if (pdata->rep) 244 __set_bit(EV_REP, input_dev->evbit); 245 246 ret = matrix_keypad_build_keymap(pdata->keymap_data, NULL, 247 pdata->rows, pdata->cols, 248 omap_kp->keymap, input_dev); 249 if (ret < 0) 250 goto err3; 251 252 ret = input_register_device(omap_kp->input); 253 if (ret < 0) { 254 printk(KERN_ERR "Unable to register omap-keypad input device\n"); 255 goto err3; 256 } 257 258 if (pdata->dbounce) 259 omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING); 260 261 /* scan current status and enable interrupt */ 262 omap_kp_scan_keypad(omap_kp, keypad_state); 263 omap_kp->irq = platform_get_irq(pdev, 0); 264 if (omap_kp->irq >= 0) { 265 if (request_irq(omap_kp->irq, omap_kp_interrupt, 0, 266 "omap-keypad", omap_kp) < 0) 267 goto err4; 268 } 269 omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 270 271 return 0; 272 273 err4: 274 input_unregister_device(omap_kp->input); 275 input_dev = NULL; 276 err3: 277 device_remove_file(&pdev->dev, &dev_attr_enable); 278 err2: 279 for (i = row_idx - 1; i >= 0; i--) 280 gpio_free(row_gpios[i]); 281 for (i = col_idx - 1; i >= 0; i--) 282 gpio_free(col_gpios[i]); 283 284 kfree(omap_kp); 285 input_free_device(input_dev); 286 287 return -EINVAL; 288 } 289 290 static int omap_kp_remove(struct platform_device *pdev) 291 { 292 struct omap_kp *omap_kp = platform_get_drvdata(pdev); 293 294 /* disable keypad interrupt handling */ 295 tasklet_disable(&kp_tasklet); 296 omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 297 free_irq(omap_kp->irq, omap_kp); 298 299 timer_shutdown_sync(&omap_kp->timer); 300 tasklet_kill(&kp_tasklet); 301 302 /* unregister everything */ 303 input_unregister_device(omap_kp->input); 304 305 kfree(omap_kp); 306 307 return 0; 308 } 309 310 static struct platform_driver omap_kp_driver = { 311 .probe = omap_kp_probe, 312 .remove = omap_kp_remove, 313 .driver = { 314 .name = "omap-keypad", 315 }, 316 }; 317 module_platform_driver(omap_kp_driver); 318 319 MODULE_AUTHOR("Timo Teräs"); 320 MODULE_DESCRIPTION("OMAP Keypad Driver"); 321 MODULE_LICENSE("GPL"); 322 MODULE_ALIAS("platform:omap-keypad"); 323