Path: blob/master/drivers/input/keyboard/matrix_keypad.c
15112 views
/*1* GPIO driven matrix keyboard driver2*3* Copyright (c) 2008 Marek Vasut <[email protected]>4*5* Based on corgikbd.c6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License version 2 as9* published by the Free Software Foundation.10*11*/1213#include <linux/types.h>14#include <linux/delay.h>15#include <linux/platform_device.h>16#include <linux/init.h>17#include <linux/input.h>18#include <linux/irq.h>19#include <linux/interrupt.h>20#include <linux/jiffies.h>21#include <linux/module.h>22#include <linux/gpio.h>23#include <linux/input/matrix_keypad.h>24#include <linux/slab.h>2526struct matrix_keypad {27const struct matrix_keypad_platform_data *pdata;28struct input_dev *input_dev;29unsigned short *keycodes;30unsigned int row_shift;3132DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS);3334uint32_t last_key_state[MATRIX_MAX_COLS];35struct delayed_work work;36spinlock_t lock;37bool scan_pending;38bool stopped;39bool gpio_all_disabled;40};4142/*43* NOTE: normally the GPIO has to be put into HiZ when de-activated to cause44* minmal side effect when scanning other columns, here it is configured to45* be input, and it should work on most platforms.46*/47static void __activate_col(const struct matrix_keypad_platform_data *pdata,48int col, bool on)49{50bool level_on = !pdata->active_low;5152if (on) {53gpio_direction_output(pdata->col_gpios[col], level_on);54} else {55gpio_set_value_cansleep(pdata->col_gpios[col], !level_on);56gpio_direction_input(pdata->col_gpios[col]);57}58}5960static void activate_col(const struct matrix_keypad_platform_data *pdata,61int col, bool on)62{63__activate_col(pdata, col, on);6465if (on && pdata->col_scan_delay_us)66udelay(pdata->col_scan_delay_us);67}6869static void activate_all_cols(const struct matrix_keypad_platform_data *pdata,70bool on)71{72int col;7374for (col = 0; col < pdata->num_col_gpios; col++)75__activate_col(pdata, col, on);76}7778static bool row_asserted(const struct matrix_keypad_platform_data *pdata,79int row)80{81return gpio_get_value_cansleep(pdata->row_gpios[row]) ?82!pdata->active_low : pdata->active_low;83}8485static void enable_row_irqs(struct matrix_keypad *keypad)86{87const struct matrix_keypad_platform_data *pdata = keypad->pdata;88int i;8990if (pdata->clustered_irq > 0)91enable_irq(pdata->clustered_irq);92else {93for (i = 0; i < pdata->num_row_gpios; i++)94enable_irq(gpio_to_irq(pdata->row_gpios[i]));95}96}9798static void disable_row_irqs(struct matrix_keypad *keypad)99{100const struct matrix_keypad_platform_data *pdata = keypad->pdata;101int i;102103if (pdata->clustered_irq > 0)104disable_irq_nosync(pdata->clustered_irq);105else {106for (i = 0; i < pdata->num_row_gpios; i++)107disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));108}109}110111/*112* This gets the keys from keyboard and reports it to input subsystem113*/114static void matrix_keypad_scan(struct work_struct *work)115{116struct matrix_keypad *keypad =117container_of(work, struct matrix_keypad, work.work);118struct input_dev *input_dev = keypad->input_dev;119const struct matrix_keypad_platform_data *pdata = keypad->pdata;120uint32_t new_state[MATRIX_MAX_COLS];121int row, col, code;122123/* de-activate all columns for scanning */124activate_all_cols(pdata, false);125126memset(new_state, 0, sizeof(new_state));127128/* assert each column and read the row status out */129for (col = 0; col < pdata->num_col_gpios; col++) {130131activate_col(pdata, col, true);132133for (row = 0; row < pdata->num_row_gpios; row++)134new_state[col] |=135row_asserted(pdata, row) ? (1 << row) : 0;136137activate_col(pdata, col, false);138}139140for (col = 0; col < pdata->num_col_gpios; col++) {141uint32_t bits_changed;142143bits_changed = keypad->last_key_state[col] ^ new_state[col];144if (bits_changed == 0)145continue;146147for (row = 0; row < pdata->num_row_gpios; row++) {148if ((bits_changed & (1 << row)) == 0)149continue;150151code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);152input_event(input_dev, EV_MSC, MSC_SCAN, code);153input_report_key(input_dev,154keypad->keycodes[code],155new_state[col] & (1 << row));156}157}158input_sync(input_dev);159160memcpy(keypad->last_key_state, new_state, sizeof(new_state));161162activate_all_cols(pdata, true);163164/* Enable IRQs again */165spin_lock_irq(&keypad->lock);166keypad->scan_pending = false;167enable_row_irqs(keypad);168spin_unlock_irq(&keypad->lock);169}170171static irqreturn_t matrix_keypad_interrupt(int irq, void *id)172{173struct matrix_keypad *keypad = id;174unsigned long flags;175176spin_lock_irqsave(&keypad->lock, flags);177178/*179* See if another IRQ beaten us to it and scheduled the180* scan already. In that case we should not try to181* disable IRQs again.182*/183if (unlikely(keypad->scan_pending || keypad->stopped))184goto out;185186disable_row_irqs(keypad);187keypad->scan_pending = true;188schedule_delayed_work(&keypad->work,189msecs_to_jiffies(keypad->pdata->debounce_ms));190191out:192spin_unlock_irqrestore(&keypad->lock, flags);193return IRQ_HANDLED;194}195196static int matrix_keypad_start(struct input_dev *dev)197{198struct matrix_keypad *keypad = input_get_drvdata(dev);199200keypad->stopped = false;201mb();202203/*204* Schedule an immediate key scan to capture current key state;205* columns will be activated and IRQs be enabled after the scan.206*/207schedule_delayed_work(&keypad->work, 0);208209return 0;210}211212static void matrix_keypad_stop(struct input_dev *dev)213{214struct matrix_keypad *keypad = input_get_drvdata(dev);215216keypad->stopped = true;217mb();218flush_work(&keypad->work.work);219/*220* matrix_keypad_scan() will leave IRQs enabled;221* we should disable them now.222*/223disable_row_irqs(keypad);224}225226#ifdef CONFIG_PM227static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)228{229const struct matrix_keypad_platform_data *pdata = keypad->pdata;230unsigned int gpio;231int i;232233if (pdata->clustered_irq > 0) {234if (enable_irq_wake(pdata->clustered_irq) == 0)235keypad->gpio_all_disabled = true;236} else {237238for (i = 0; i < pdata->num_row_gpios; i++) {239if (!test_bit(i, keypad->disabled_gpios)) {240gpio = pdata->row_gpios[i];241242if (enable_irq_wake(gpio_to_irq(gpio)) == 0)243__set_bit(i, keypad->disabled_gpios);244}245}246}247}248249static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)250{251const struct matrix_keypad_platform_data *pdata = keypad->pdata;252unsigned int gpio;253int i;254255if (pdata->clustered_irq > 0) {256if (keypad->gpio_all_disabled) {257disable_irq_wake(pdata->clustered_irq);258keypad->gpio_all_disabled = false;259}260} else {261for (i = 0; i < pdata->num_row_gpios; i++) {262if (test_and_clear_bit(i, keypad->disabled_gpios)) {263gpio = pdata->row_gpios[i];264disable_irq_wake(gpio_to_irq(gpio));265}266}267}268}269270static int matrix_keypad_suspend(struct device *dev)271{272struct platform_device *pdev = to_platform_device(dev);273struct matrix_keypad *keypad = platform_get_drvdata(pdev);274275matrix_keypad_stop(keypad->input_dev);276277if (device_may_wakeup(&pdev->dev))278matrix_keypad_enable_wakeup(keypad);279280return 0;281}282283static int matrix_keypad_resume(struct device *dev)284{285struct platform_device *pdev = to_platform_device(dev);286struct matrix_keypad *keypad = platform_get_drvdata(pdev);287288if (device_may_wakeup(&pdev->dev))289matrix_keypad_disable_wakeup(keypad);290291matrix_keypad_start(keypad->input_dev);292293return 0;294}295296static const SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,297matrix_keypad_suspend, matrix_keypad_resume);298#endif299300static int __devinit init_matrix_gpio(struct platform_device *pdev,301struct matrix_keypad *keypad)302{303const struct matrix_keypad_platform_data *pdata = keypad->pdata;304int i, err = -EINVAL;305306/* initialized strobe lines as outputs, activated */307for (i = 0; i < pdata->num_col_gpios; i++) {308err = gpio_request(pdata->col_gpios[i], "matrix_kbd_col");309if (err) {310dev_err(&pdev->dev,311"failed to request GPIO%d for COL%d\n",312pdata->col_gpios[i], i);313goto err_free_cols;314}315316gpio_direction_output(pdata->col_gpios[i], !pdata->active_low);317}318319for (i = 0; i < pdata->num_row_gpios; i++) {320err = gpio_request(pdata->row_gpios[i], "matrix_kbd_row");321if (err) {322dev_err(&pdev->dev,323"failed to request GPIO%d for ROW%d\n",324pdata->row_gpios[i], i);325goto err_free_rows;326}327328gpio_direction_input(pdata->row_gpios[i]);329}330331if (pdata->clustered_irq > 0) {332err = request_irq(pdata->clustered_irq,333matrix_keypad_interrupt,334pdata->clustered_irq_flags,335"matrix-keypad", keypad);336if (err) {337dev_err(&pdev->dev,338"Unable to acquire clustered interrupt\n");339goto err_free_rows;340}341} else {342for (i = 0; i < pdata->num_row_gpios; i++) {343err = request_irq(gpio_to_irq(pdata->row_gpios[i]),344matrix_keypad_interrupt,345IRQF_DISABLED |346IRQF_TRIGGER_RISING |347IRQF_TRIGGER_FALLING,348"matrix-keypad", keypad);349if (err) {350dev_err(&pdev->dev,351"Unable to acquire interrupt "352"for GPIO line %i\n",353pdata->row_gpios[i]);354goto err_free_irqs;355}356}357}358359/* initialized as disabled - enabled by input->open */360disable_row_irqs(keypad);361return 0;362363err_free_irqs:364while (--i >= 0)365free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);366i = pdata->num_row_gpios;367err_free_rows:368while (--i >= 0)369gpio_free(pdata->row_gpios[i]);370i = pdata->num_col_gpios;371err_free_cols:372while (--i >= 0)373gpio_free(pdata->col_gpios[i]);374375return err;376}377378static int __devinit matrix_keypad_probe(struct platform_device *pdev)379{380const struct matrix_keypad_platform_data *pdata;381const struct matrix_keymap_data *keymap_data;382struct matrix_keypad *keypad;383struct input_dev *input_dev;384unsigned short *keycodes;385unsigned int row_shift;386int err;387388pdata = pdev->dev.platform_data;389if (!pdata) {390dev_err(&pdev->dev, "no platform data defined\n");391return -EINVAL;392}393394keymap_data = pdata->keymap_data;395if (!keymap_data) {396dev_err(&pdev->dev, "no keymap data defined\n");397return -EINVAL;398}399400row_shift = get_count_order(pdata->num_col_gpios);401402keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL);403keycodes = kzalloc((pdata->num_row_gpios << row_shift) *404sizeof(*keycodes),405GFP_KERNEL);406input_dev = input_allocate_device();407if (!keypad || !keycodes || !input_dev) {408err = -ENOMEM;409goto err_free_mem;410}411412keypad->input_dev = input_dev;413keypad->pdata = pdata;414keypad->keycodes = keycodes;415keypad->row_shift = row_shift;416keypad->stopped = true;417INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);418spin_lock_init(&keypad->lock);419420input_dev->name = pdev->name;421input_dev->id.bustype = BUS_HOST;422input_dev->dev.parent = &pdev->dev;423input_dev->evbit[0] = BIT_MASK(EV_KEY);424if (!pdata->no_autorepeat)425input_dev->evbit[0] |= BIT_MASK(EV_REP);426input_dev->open = matrix_keypad_start;427input_dev->close = matrix_keypad_stop;428429input_dev->keycode = keycodes;430input_dev->keycodesize = sizeof(*keycodes);431input_dev->keycodemax = pdata->num_row_gpios << row_shift;432433matrix_keypad_build_keymap(keymap_data, row_shift,434input_dev->keycode, input_dev->keybit);435436input_set_capability(input_dev, EV_MSC, MSC_SCAN);437input_set_drvdata(input_dev, keypad);438439err = init_matrix_gpio(pdev, keypad);440if (err)441goto err_free_mem;442443err = input_register_device(keypad->input_dev);444if (err)445goto err_free_mem;446447device_init_wakeup(&pdev->dev, pdata->wakeup);448platform_set_drvdata(pdev, keypad);449450return 0;451452err_free_mem:453input_free_device(input_dev);454kfree(keycodes);455kfree(keypad);456return err;457}458459static int __devexit matrix_keypad_remove(struct platform_device *pdev)460{461struct matrix_keypad *keypad = platform_get_drvdata(pdev);462const struct matrix_keypad_platform_data *pdata = keypad->pdata;463int i;464465device_init_wakeup(&pdev->dev, 0);466467if (pdata->clustered_irq > 0) {468free_irq(pdata->clustered_irq, keypad);469} else {470for (i = 0; i < pdata->num_row_gpios; i++)471free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);472}473474for (i = 0; i < pdata->num_row_gpios; i++)475gpio_free(pdata->row_gpios[i]);476477for (i = 0; i < pdata->num_col_gpios; i++)478gpio_free(pdata->col_gpios[i]);479480input_unregister_device(keypad->input_dev);481platform_set_drvdata(pdev, NULL);482kfree(keypad->keycodes);483kfree(keypad);484485return 0;486}487488static struct platform_driver matrix_keypad_driver = {489.probe = matrix_keypad_probe,490.remove = __devexit_p(matrix_keypad_remove),491.driver = {492.name = "matrix-keypad",493.owner = THIS_MODULE,494#ifdef CONFIG_PM495.pm = &matrix_keypad_pm_ops,496#endif497},498};499500static int __init matrix_keypad_init(void)501{502return platform_driver_register(&matrix_keypad_driver);503}504505static void __exit matrix_keypad_exit(void)506{507platform_driver_unregister(&matrix_keypad_driver);508}509510module_init(matrix_keypad_init);511module_exit(matrix_keypad_exit);512513MODULE_AUTHOR("Marek Vasut <[email protected]>");514MODULE_DESCRIPTION("GPIO Driven Matrix Keypad Driver");515MODULE_LICENSE("GPL v2");516MODULE_ALIAS("platform:matrix-keypad");517518519