Path: blob/master/drivers/input/keyboard/gpio_keys.c
15112 views
/*1* Driver for keys on GPIO lines capable of generating interrupts.2*3* Copyright 2005 Phil Blundell4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License version 2 as7* published by the Free Software Foundation.8*/910#include <linux/module.h>1112#include <linux/init.h>13#include <linux/fs.h>14#include <linux/interrupt.h>15#include <linux/irq.h>16#include <linux/sched.h>17#include <linux/pm.h>18#include <linux/slab.h>19#include <linux/sysctl.h>20#include <linux/proc_fs.h>21#include <linux/delay.h>22#include <linux/platform_device.h>23#include <linux/input.h>24#include <linux/gpio_keys.h>25#include <linux/workqueue.h>26#include <linux/gpio.h>2728struct gpio_button_data {29struct gpio_keys_button *button;30struct input_dev *input;31struct timer_list timer;32struct work_struct work;33int timer_debounce; /* in msecs */34bool disabled;35};3637struct gpio_keys_drvdata {38struct input_dev *input;39struct mutex disable_lock;40unsigned int n_buttons;41int (*enable)(struct device *dev);42void (*disable)(struct device *dev);43struct gpio_button_data data[0];44};4546/*47* SYSFS interface for enabling/disabling keys and switches:48*49* There are 4 attributes under /sys/devices/platform/gpio-keys/50* keys [ro] - bitmap of keys (EV_KEY) which can be51* disabled52* switches [ro] - bitmap of switches (EV_SW) which can be53* disabled54* disabled_keys [rw] - bitmap of keys currently disabled55* disabled_switches [rw] - bitmap of switches currently disabled56*57* Userland can change these values and hence disable event generation58* for each key (or switch). Disabling a key means its interrupt line59* is disabled.60*61* For example, if we have following switches set up as gpio-keys:62* SW_DOCK = 563* SW_CAMERA_LENS_COVER = 964* SW_KEYPAD_SLIDE = 1065* SW_FRONT_PROXIMITY = 1166* This is read from switches:67* 11-9,568* Next we want to disable proximity (11) and dock (5), we write:69* 11,570* to file disabled_switches. Now proximity and dock IRQs are disabled.71* This can be verified by reading the file disabled_switches:72* 11,573* If we now want to enable proximity (11) switch we write:74* 575* to disabled_switches.76*77* We can disable only those keys which don't allow sharing the irq.78*/7980/**81* get_n_events_by_type() - returns maximum number of events per @type82* @type: type of button (%EV_KEY, %EV_SW)83*84* Return value of this function can be used to allocate bitmap85* large enough to hold all bits for given type.86*/87static inline int get_n_events_by_type(int type)88{89BUG_ON(type != EV_SW && type != EV_KEY);9091return (type == EV_KEY) ? KEY_CNT : SW_CNT;92}9394/**95* gpio_keys_disable_button() - disables given GPIO button96* @bdata: button data for button to be disabled97*98* Disables button pointed by @bdata. This is done by masking99* IRQ line. After this function is called, button won't generate100* input events anymore. Note that one can only disable buttons101* that don't share IRQs.102*103* Make sure that @bdata->disable_lock is locked when entering104* this function to avoid races when concurrent threads are105* disabling buttons at the same time.106*/107static void gpio_keys_disable_button(struct gpio_button_data *bdata)108{109if (!bdata->disabled) {110/*111* Disable IRQ and possible debouncing timer.112*/113disable_irq(gpio_to_irq(bdata->button->gpio));114if (bdata->timer_debounce)115del_timer_sync(&bdata->timer);116117bdata->disabled = true;118}119}120121/**122* gpio_keys_enable_button() - enables given GPIO button123* @bdata: button data for button to be disabled124*125* Enables given button pointed by @bdata.126*127* Make sure that @bdata->disable_lock is locked when entering128* this function to avoid races with concurrent threads trying129* to enable the same button at the same time.130*/131static void gpio_keys_enable_button(struct gpio_button_data *bdata)132{133if (bdata->disabled) {134enable_irq(gpio_to_irq(bdata->button->gpio));135bdata->disabled = false;136}137}138139/**140* gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons141* @ddata: pointer to drvdata142* @buf: buffer where stringified bitmap is written143* @type: button type (%EV_KEY, %EV_SW)144* @only_disabled: does caller want only those buttons that are145* currently disabled or all buttons that can be146* disabled147*148* This function writes buttons that can be disabled to @buf. If149* @only_disabled is true, then @buf contains only those buttons150* that are currently disabled. Returns 0 on success or negative151* errno on failure.152*/153static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,154char *buf, unsigned int type,155bool only_disabled)156{157int n_events = get_n_events_by_type(type);158unsigned long *bits;159ssize_t ret;160int i;161162bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);163if (!bits)164return -ENOMEM;165166for (i = 0; i < ddata->n_buttons; i++) {167struct gpio_button_data *bdata = &ddata->data[i];168169if (bdata->button->type != type)170continue;171172if (only_disabled && !bdata->disabled)173continue;174175__set_bit(bdata->button->code, bits);176}177178ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events);179buf[ret++] = '\n';180buf[ret] = '\0';181182kfree(bits);183184return ret;185}186187/**188* gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap189* @ddata: pointer to drvdata190* @buf: buffer from userspace that contains stringified bitmap191* @type: button type (%EV_KEY, %EV_SW)192*193* This function parses stringified bitmap from @buf and disables/enables194* GPIO buttons accordinly. Returns 0 on success and negative error195* on failure.196*/197static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,198const char *buf, unsigned int type)199{200int n_events = get_n_events_by_type(type);201unsigned long *bits;202ssize_t error;203int i;204205bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);206if (!bits)207return -ENOMEM;208209error = bitmap_parselist(buf, bits, n_events);210if (error)211goto out;212213/* First validate */214for (i = 0; i < ddata->n_buttons; i++) {215struct gpio_button_data *bdata = &ddata->data[i];216217if (bdata->button->type != type)218continue;219220if (test_bit(bdata->button->code, bits) &&221!bdata->button->can_disable) {222error = -EINVAL;223goto out;224}225}226227mutex_lock(&ddata->disable_lock);228229for (i = 0; i < ddata->n_buttons; i++) {230struct gpio_button_data *bdata = &ddata->data[i];231232if (bdata->button->type != type)233continue;234235if (test_bit(bdata->button->code, bits))236gpio_keys_disable_button(bdata);237else238gpio_keys_enable_button(bdata);239}240241mutex_unlock(&ddata->disable_lock);242243out:244kfree(bits);245return error;246}247248#define ATTR_SHOW_FN(name, type, only_disabled) \249static ssize_t gpio_keys_show_##name(struct device *dev, \250struct device_attribute *attr, \251char *buf) \252{ \253struct platform_device *pdev = to_platform_device(dev); \254struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \255\256return gpio_keys_attr_show_helper(ddata, buf, \257type, only_disabled); \258}259260ATTR_SHOW_FN(keys, EV_KEY, false);261ATTR_SHOW_FN(switches, EV_SW, false);262ATTR_SHOW_FN(disabled_keys, EV_KEY, true);263ATTR_SHOW_FN(disabled_switches, EV_SW, true);264265/*266* ATTRIBUTES:267*268* /sys/devices/platform/gpio-keys/keys [ro]269* /sys/devices/platform/gpio-keys/switches [ro]270*/271static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);272static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);273274#define ATTR_STORE_FN(name, type) \275static ssize_t gpio_keys_store_##name(struct device *dev, \276struct device_attribute *attr, \277const char *buf, \278size_t count) \279{ \280struct platform_device *pdev = to_platform_device(dev); \281struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \282ssize_t error; \283\284error = gpio_keys_attr_store_helper(ddata, buf, type); \285if (error) \286return error; \287\288return count; \289}290291ATTR_STORE_FN(disabled_keys, EV_KEY);292ATTR_STORE_FN(disabled_switches, EV_SW);293294/*295* ATTRIBUTES:296*297* /sys/devices/platform/gpio-keys/disabled_keys [rw]298* /sys/devices/platform/gpio-keys/disables_switches [rw]299*/300static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,301gpio_keys_show_disabled_keys,302gpio_keys_store_disabled_keys);303static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,304gpio_keys_show_disabled_switches,305gpio_keys_store_disabled_switches);306307static struct attribute *gpio_keys_attrs[] = {308&dev_attr_keys.attr,309&dev_attr_switches.attr,310&dev_attr_disabled_keys.attr,311&dev_attr_disabled_switches.attr,312NULL,313};314315static struct attribute_group gpio_keys_attr_group = {316.attrs = gpio_keys_attrs,317};318319static void gpio_keys_report_event(struct gpio_button_data *bdata)320{321struct gpio_keys_button *button = bdata->button;322struct input_dev *input = bdata->input;323unsigned int type = button->type ?: EV_KEY;324int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;325326if (type == EV_ABS) {327if (state)328input_event(input, type, button->code, button->value);329} else {330input_event(input, type, button->code, !!state);331}332input_sync(input);333}334335static void gpio_keys_work_func(struct work_struct *work)336{337struct gpio_button_data *bdata =338container_of(work, struct gpio_button_data, work);339340gpio_keys_report_event(bdata);341}342343static void gpio_keys_timer(unsigned long _data)344{345struct gpio_button_data *data = (struct gpio_button_data *)_data;346347schedule_work(&data->work);348}349350static irqreturn_t gpio_keys_isr(int irq, void *dev_id)351{352struct gpio_button_data *bdata = dev_id;353struct gpio_keys_button *button = bdata->button;354355BUG_ON(irq != gpio_to_irq(button->gpio));356357if (bdata->timer_debounce)358mod_timer(&bdata->timer,359jiffies + msecs_to_jiffies(bdata->timer_debounce));360else361schedule_work(&bdata->work);362363return IRQ_HANDLED;364}365366static int __devinit gpio_keys_setup_key(struct platform_device *pdev,367struct gpio_button_data *bdata,368struct gpio_keys_button *button)369{370const char *desc = button->desc ? button->desc : "gpio_keys";371struct device *dev = &pdev->dev;372unsigned long irqflags;373int irq, error;374375setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);376INIT_WORK(&bdata->work, gpio_keys_work_func);377378error = gpio_request(button->gpio, desc);379if (error < 0) {380dev_err(dev, "failed to request GPIO %d, error %d\n",381button->gpio, error);382goto fail2;383}384385error = gpio_direction_input(button->gpio);386if (error < 0) {387dev_err(dev, "failed to configure"388" direction for GPIO %d, error %d\n",389button->gpio, error);390goto fail3;391}392393if (button->debounce_interval) {394error = gpio_set_debounce(button->gpio,395button->debounce_interval * 1000);396/* use timer if gpiolib doesn't provide debounce */397if (error < 0)398bdata->timer_debounce = button->debounce_interval;399}400401irq = gpio_to_irq(button->gpio);402if (irq < 0) {403error = irq;404dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n",405button->gpio, error);406goto fail3;407}408409irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;410/*411* If platform has specified that the button can be disabled,412* we don't want it to share the interrupt line.413*/414if (!button->can_disable)415irqflags |= IRQF_SHARED;416417error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata);418if (error < 0) {419dev_err(dev, "Unable to claim irq %d; error %d\n",420irq, error);421goto fail3;422}423424return 0;425426fail3:427gpio_free(button->gpio);428fail2:429return error;430}431432static int gpio_keys_open(struct input_dev *input)433{434struct gpio_keys_drvdata *ddata = input_get_drvdata(input);435436return ddata->enable ? ddata->enable(input->dev.parent) : 0;437}438439static void gpio_keys_close(struct input_dev *input)440{441struct gpio_keys_drvdata *ddata = input_get_drvdata(input);442443if (ddata->disable)444ddata->disable(input->dev.parent);445}446447static int __devinit gpio_keys_probe(struct platform_device *pdev)448{449struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;450struct gpio_keys_drvdata *ddata;451struct device *dev = &pdev->dev;452struct input_dev *input;453int i, error;454int wakeup = 0;455456ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +457pdata->nbuttons * sizeof(struct gpio_button_data),458GFP_KERNEL);459input = input_allocate_device();460if (!ddata || !input) {461dev_err(dev, "failed to allocate state\n");462error = -ENOMEM;463goto fail1;464}465466ddata->input = input;467ddata->n_buttons = pdata->nbuttons;468ddata->enable = pdata->enable;469ddata->disable = pdata->disable;470mutex_init(&ddata->disable_lock);471472platform_set_drvdata(pdev, ddata);473input_set_drvdata(input, ddata);474475input->name = pdata->name ? : pdev->name;476input->phys = "gpio-keys/input0";477input->dev.parent = &pdev->dev;478input->open = gpio_keys_open;479input->close = gpio_keys_close;480481input->id.bustype = BUS_HOST;482input->id.vendor = 0x0001;483input->id.product = 0x0001;484input->id.version = 0x0100;485486/* Enable auto repeat feature of Linux input subsystem */487if (pdata->rep)488__set_bit(EV_REP, input->evbit);489490for (i = 0; i < pdata->nbuttons; i++) {491struct gpio_keys_button *button = &pdata->buttons[i];492struct gpio_button_data *bdata = &ddata->data[i];493unsigned int type = button->type ?: EV_KEY;494495bdata->input = input;496bdata->button = button;497498error = gpio_keys_setup_key(pdev, bdata, button);499if (error)500goto fail2;501502if (button->wakeup)503wakeup = 1;504505input_set_capability(input, type, button->code);506}507508error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);509if (error) {510dev_err(dev, "Unable to export keys/switches, error: %d\n",511error);512goto fail2;513}514515error = input_register_device(input);516if (error) {517dev_err(dev, "Unable to register input device, error: %d\n",518error);519goto fail3;520}521522/* get current state of buttons */523for (i = 0; i < pdata->nbuttons; i++)524gpio_keys_report_event(&ddata->data[i]);525input_sync(input);526527device_init_wakeup(&pdev->dev, wakeup);528529return 0;530531fail3:532sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);533fail2:534while (--i >= 0) {535free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);536if (ddata->data[i].timer_debounce)537del_timer_sync(&ddata->data[i].timer);538cancel_work_sync(&ddata->data[i].work);539gpio_free(pdata->buttons[i].gpio);540}541542platform_set_drvdata(pdev, NULL);543fail1:544input_free_device(input);545kfree(ddata);546547return error;548}549550static int __devexit gpio_keys_remove(struct platform_device *pdev)551{552struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;553struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);554struct input_dev *input = ddata->input;555int i;556557sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);558559device_init_wakeup(&pdev->dev, 0);560561for (i = 0; i < pdata->nbuttons; i++) {562int irq = gpio_to_irq(pdata->buttons[i].gpio);563free_irq(irq, &ddata->data[i]);564if (ddata->data[i].timer_debounce)565del_timer_sync(&ddata->data[i].timer);566cancel_work_sync(&ddata->data[i].work);567gpio_free(pdata->buttons[i].gpio);568}569570input_unregister_device(input);571572return 0;573}574575576#ifdef CONFIG_PM577static int gpio_keys_suspend(struct device *dev)578{579struct platform_device *pdev = to_platform_device(dev);580struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;581int i;582583if (device_may_wakeup(&pdev->dev)) {584for (i = 0; i < pdata->nbuttons; i++) {585struct gpio_keys_button *button = &pdata->buttons[i];586if (button->wakeup) {587int irq = gpio_to_irq(button->gpio);588enable_irq_wake(irq);589}590}591}592593return 0;594}595596static int gpio_keys_resume(struct device *dev)597{598struct platform_device *pdev = to_platform_device(dev);599struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);600struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;601int i;602603for (i = 0; i < pdata->nbuttons; i++) {604605struct gpio_keys_button *button = &pdata->buttons[i];606if (button->wakeup && device_may_wakeup(&pdev->dev)) {607int irq = gpio_to_irq(button->gpio);608disable_irq_wake(irq);609}610611gpio_keys_report_event(&ddata->data[i]);612}613input_sync(ddata->input);614615return 0;616}617618static const struct dev_pm_ops gpio_keys_pm_ops = {619.suspend = gpio_keys_suspend,620.resume = gpio_keys_resume,621};622#endif623624static struct platform_driver gpio_keys_device_driver = {625.probe = gpio_keys_probe,626.remove = __devexit_p(gpio_keys_remove),627.driver = {628.name = "gpio-keys",629.owner = THIS_MODULE,630#ifdef CONFIG_PM631.pm = &gpio_keys_pm_ops,632#endif633}634};635636static int __init gpio_keys_init(void)637{638return platform_driver_register(&gpio_keys_device_driver);639}640641static void __exit gpio_keys_exit(void)642{643platform_driver_unregister(&gpio_keys_device_driver);644}645646module_init(gpio_keys_init);647module_exit(gpio_keys_exit);648649MODULE_LICENSE("GPL");650MODULE_AUTHOR("Phil Blundell <[email protected]>");651MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");652MODULE_ALIAS("platform:gpio-keys");653654655