0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
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
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
0075 omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
0076
0077
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
0101 omap_kp_scan_keypad(omap_kp_data, new_state);
0102
0103
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
0136
0137 mod_timer(&omap_kp_data->timer, jiffies + HZ / 20);
0138 } else {
0139
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
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
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
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
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
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
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");