Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * linux/drivers/input/keyboard/omap-keypad.c
0004  *
0005  * OMAP Keypad Driver
0006  *
0007  * Copyright (C) 2003 Nokia Corporation
0008  * Written by Timo Teräs <ext-timo.teras@nokia.com>
0009  *
0010  * Added support for H2 & H3 Keypad
0011  * Copyright (C) 2004 Texas Instruments
0012  */
0013 
0014 #include <linux/module.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/types.h>
0017 #include <linux/input.h>
0018 #include <linux/kernel.h>
0019 #include <linux/delay.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/mutex.h>
0022 #include <linux/errno.h>
0023 #include <linux/slab.h>
0024 #include <linux/gpio.h>
0025 #include <linux/platform_data/gpio-omap.h>
0026 #include <linux/platform_data/keypad-omap.h>
0027 #include <linux/soc/ti/omap1-io.h>
0028 
0029 #undef NEW_BOARD_LEARNING_MODE
0030 
0031 static void omap_kp_tasklet(unsigned long);
0032 static void omap_kp_timer(struct timer_list *);
0033 
0034 static unsigned char keypad_state[8];
0035 static DEFINE_MUTEX(kp_enable_mutex);
0036 static int kp_enable = 1;
0037 static int kp_cur_group = -1;
0038 
0039 struct omap_kp {
0040     struct input_dev *input;
0041     struct timer_list timer;
0042     int irq;
0043     unsigned int rows;
0044     unsigned int cols;
0045     unsigned long delay;
0046     unsigned int debounce;
0047     unsigned short keymap[];
0048 };
0049 
0050 static DECLARE_TASKLET_DISABLED_OLD(kp_tasklet, omap_kp_tasklet);
0051 
0052 static unsigned int *row_gpios;
0053 static unsigned int *col_gpios;
0054 
0055 static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
0056 {
0057     /* disable keyboard interrupt and schedule for handling */
0058     omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
0059 
0060     tasklet_schedule(&kp_tasklet);
0061 
0062     return IRQ_HANDLED;
0063 }
0064 
0065 static void omap_kp_timer(struct timer_list *unused)
0066 {
0067     tasklet_schedule(&kp_tasklet);
0068 }
0069 
0070 static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
0071 {
0072     int col = 0;
0073 
0074     /* disable keyboard interrupt and schedule for handling */
0075     omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
0076 
0077     /* read the keypad status */
0078     omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
0079     for (col = 0; col < omap_kp->cols; col++) {
0080         omap_writew(~(1 << col) & 0xff,
0081                 OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
0082 
0083         udelay(omap_kp->delay);
0084 
0085         state[col] = ~omap_readw(OMAP1_MPUIO_BASE +
0086                      OMAP_MPUIO_KBR_LATCH) & 0xff;
0087     }
0088     omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
0089     udelay(2);
0090 }
0091 
0092 static void omap_kp_tasklet(unsigned long data)
0093 {
0094     struct omap_kp *omap_kp_data = (struct omap_kp *) data;
0095     unsigned short *keycodes = omap_kp_data->input->keycode;
0096     unsigned int row_shift = get_count_order(omap_kp_data->cols);
0097     unsigned char new_state[8], changed, key_down = 0;
0098     int col, row;
0099 
0100     /* check for any changes */
0101     omap_kp_scan_keypad(omap_kp_data, new_state);
0102 
0103     /* check for changes and print those */
0104     for (col = 0; col < omap_kp_data->cols; col++) {
0105         changed = new_state[col] ^ keypad_state[col];
0106         key_down |= new_state[col];
0107         if (changed == 0)
0108             continue;
0109 
0110         for (row = 0; row < omap_kp_data->rows; row++) {
0111             int key;
0112             if (!(changed & (1 << row)))
0113                 continue;
0114 #ifdef NEW_BOARD_LEARNING_MODE
0115             printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col,
0116                    row, (new_state[col] & (1 << row)) ?
0117                    "pressed" : "released");
0118 #else
0119             key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)];
0120 
0121             if (!(kp_cur_group == (key & GROUP_MASK) ||
0122                   kp_cur_group == -1))
0123                 continue;
0124 
0125             kp_cur_group = key & GROUP_MASK;
0126             input_report_key(omap_kp_data->input, key & ~GROUP_MASK,
0127                      new_state[col] & (1 << row));
0128 #endif
0129         }
0130     }
0131     input_sync(omap_kp_data->input);
0132     memcpy(keypad_state, new_state, sizeof(keypad_state));
0133 
0134     if (key_down) {
0135         /* some key is pressed - keep irq disabled and use timer
0136          * to poll the keypad */
0137         mod_timer(&omap_kp_data->timer, jiffies + HZ / 20);
0138     } else {
0139         /* enable interrupts */
0140         omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
0141         kp_cur_group = -1;
0142     }
0143 }
0144 
0145 static ssize_t omap_kp_enable_show(struct device *dev,
0146                    struct device_attribute *attr, char *buf)
0147 {
0148     return sprintf(buf, "%u\n", kp_enable);
0149 }
0150 
0151 static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
0152                     const char *buf, size_t count)
0153 {
0154     struct omap_kp *omap_kp = dev_get_drvdata(dev);
0155     int state;
0156 
0157     if (sscanf(buf, "%u", &state) != 1)
0158         return -EINVAL;
0159 
0160     if ((state != 1) && (state != 0))
0161         return -EINVAL;
0162 
0163     mutex_lock(&kp_enable_mutex);
0164     if (state != kp_enable) {
0165         if (state)
0166             enable_irq(omap_kp->irq);
0167         else
0168             disable_irq(omap_kp->irq);
0169         kp_enable = state;
0170     }
0171     mutex_unlock(&kp_enable_mutex);
0172 
0173     return strnlen(buf, count);
0174 }
0175 
0176 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
0177 
0178 static int omap_kp_probe(struct platform_device *pdev)
0179 {
0180     struct omap_kp *omap_kp;
0181     struct input_dev *input_dev;
0182     struct omap_kp_platform_data *pdata = dev_get_platdata(&pdev->dev);
0183     int i, col_idx, row_idx, ret;
0184     unsigned int row_shift, keycodemax;
0185 
0186     if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
0187         printk(KERN_ERR "No rows, cols or keymap_data from pdata\n");
0188         return -EINVAL;
0189     }
0190 
0191     row_shift = get_count_order(pdata->cols);
0192     keycodemax = pdata->rows << row_shift;
0193 
0194     omap_kp = kzalloc(struct_size(omap_kp, keymap, keycodemax), GFP_KERNEL);
0195     input_dev = input_allocate_device();
0196     if (!omap_kp || !input_dev) {
0197         kfree(omap_kp);
0198         input_free_device(input_dev);
0199         return -ENOMEM;
0200     }
0201 
0202     platform_set_drvdata(pdev, omap_kp);
0203 
0204     omap_kp->input = input_dev;
0205 
0206     /* Disable the interrupt for the MPUIO keyboard */
0207     omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
0208 
0209     if (pdata->delay)
0210         omap_kp->delay = pdata->delay;
0211 
0212     if (pdata->row_gpios && pdata->col_gpios) {
0213         row_gpios = pdata->row_gpios;
0214         col_gpios = pdata->col_gpios;
0215     }
0216 
0217     omap_kp->rows = pdata->rows;
0218     omap_kp->cols = pdata->cols;
0219 
0220     col_idx = 0;
0221     row_idx = 0;
0222 
0223     timer_setup(&omap_kp->timer, omap_kp_timer, 0);
0224 
0225     /* get the irq and init timer*/
0226     kp_tasklet.data = (unsigned long) omap_kp;
0227     tasklet_enable(&kp_tasklet);
0228 
0229     ret = device_create_file(&pdev->dev, &dev_attr_enable);
0230     if (ret < 0)
0231         goto err2;
0232 
0233     /* setup input device */
0234     input_dev->name = "omap-keypad";
0235     input_dev->phys = "omap-keypad/input0";
0236     input_dev->dev.parent = &pdev->dev;
0237 
0238     input_dev->id.bustype = BUS_HOST;
0239     input_dev->id.vendor = 0x0001;
0240     input_dev->id.product = 0x0001;
0241     input_dev->id.version = 0x0100;
0242 
0243     if (pdata->rep)
0244         __set_bit(EV_REP, input_dev->evbit);
0245 
0246     ret = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
0247                      pdata->rows, pdata->cols,
0248                      omap_kp->keymap, input_dev);
0249     if (ret < 0)
0250         goto err3;
0251 
0252     ret = input_register_device(omap_kp->input);
0253     if (ret < 0) {
0254         printk(KERN_ERR "Unable to register omap-keypad input device\n");
0255         goto err3;
0256     }
0257 
0258     if (pdata->dbounce)
0259         omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
0260 
0261     /* scan current status and enable interrupt */
0262     omap_kp_scan_keypad(omap_kp, keypad_state);
0263     omap_kp->irq = platform_get_irq(pdev, 0);
0264     if (omap_kp->irq >= 0) {
0265         if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
0266                 "omap-keypad", omap_kp) < 0)
0267             goto err4;
0268     }
0269     omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
0270 
0271     return 0;
0272 
0273 err4:
0274     input_unregister_device(omap_kp->input);
0275     input_dev = NULL;
0276 err3:
0277     device_remove_file(&pdev->dev, &dev_attr_enable);
0278 err2:
0279     for (i = row_idx - 1; i >= 0; i--)
0280         gpio_free(row_gpios[i]);
0281     for (i = col_idx - 1; i >= 0; i--)
0282         gpio_free(col_gpios[i]);
0283 
0284     kfree(omap_kp);
0285     input_free_device(input_dev);
0286 
0287     return -EINVAL;
0288 }
0289 
0290 static int omap_kp_remove(struct platform_device *pdev)
0291 {
0292     struct omap_kp *omap_kp = platform_get_drvdata(pdev);
0293 
0294     /* disable keypad interrupt handling */
0295     tasklet_disable(&kp_tasklet);
0296     omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
0297     free_irq(omap_kp->irq, omap_kp);
0298 
0299     del_timer_sync(&omap_kp->timer);
0300     tasklet_kill(&kp_tasklet);
0301 
0302     /* unregister everything */
0303     input_unregister_device(omap_kp->input);
0304 
0305     kfree(omap_kp);
0306 
0307     return 0;
0308 }
0309 
0310 static struct platform_driver omap_kp_driver = {
0311     .probe      = omap_kp_probe,
0312     .remove     = omap_kp_remove,
0313     .driver     = {
0314         .name   = "omap-keypad",
0315     },
0316 };
0317 module_platform_driver(omap_kp_driver);
0318 
0319 MODULE_AUTHOR("Timo Teräs");
0320 MODULE_DESCRIPTION("OMAP Keypad Driver");
0321 MODULE_LICENSE("GPL");
0322 MODULE_ALIAS("platform:omap-keypad");