Path: blob/master/drivers/input/misc/cobalt_btns.c
15109 views
/*1* Cobalt button interface driver.2*3* Copyright (C) 2007-2008 Yoichi Yuasa <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA18*/19#include <linux/init.h>20#include <linux/input-polldev.h>21#include <linux/ioport.h>22#include <linux/module.h>23#include <linux/platform_device.h>24#include <linux/slab.h>2526#define BUTTONS_POLL_INTERVAL 30 /* msec */27#define BUTTONS_COUNT_THRESHOLD 328#define BUTTONS_STATUS_MASK 0xfe0000002930static const unsigned short cobalt_map[] = {31KEY_RESERVED,32KEY_RESTART,33KEY_LEFT,34KEY_UP,35KEY_DOWN,36KEY_RIGHT,37KEY_ENTER,38KEY_SELECT39};4041struct buttons_dev {42struct input_polled_dev *poll_dev;43unsigned short keymap[ARRAY_SIZE(cobalt_map)];44int count[ARRAY_SIZE(cobalt_map)];45void __iomem *reg;46};4748static void handle_buttons(struct input_polled_dev *dev)49{50struct buttons_dev *bdev = dev->private;51struct input_dev *input = dev->input;52uint32_t status;53int i;5455status = ~readl(bdev->reg) >> 24;5657for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) {58if (status & (1U << i)) {59if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) {60input_event(input, EV_MSC, MSC_SCAN, i);61input_report_key(input, bdev->keymap[i], 1);62input_sync(input);63}64} else {65if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) {66input_event(input, EV_MSC, MSC_SCAN, i);67input_report_key(input, bdev->keymap[i], 0);68input_sync(input);69}70bdev->count[i] = 0;71}72}73}7475static int __devinit cobalt_buttons_probe(struct platform_device *pdev)76{77struct buttons_dev *bdev;78struct input_polled_dev *poll_dev;79struct input_dev *input;80struct resource *res;81int error, i;8283bdev = kzalloc(sizeof(struct buttons_dev), GFP_KERNEL);84poll_dev = input_allocate_polled_device();85if (!bdev || !poll_dev) {86error = -ENOMEM;87goto err_free_mem;88}8990memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap));9192poll_dev->private = bdev;93poll_dev->poll = handle_buttons;94poll_dev->poll_interval = BUTTONS_POLL_INTERVAL;9596input = poll_dev->input;97input->name = "Cobalt buttons";98input->phys = "cobalt/input0";99input->id.bustype = BUS_HOST;100input->dev.parent = &pdev->dev;101102input->keycode = bdev->keymap;103input->keycodemax = ARRAY_SIZE(bdev->keymap);104input->keycodesize = sizeof(unsigned short);105106input_set_capability(input, EV_MSC, MSC_SCAN);107__set_bit(EV_KEY, input->evbit);108for (i = 0; i < ARRAY_SIZE(cobalt_map); i++)109__set_bit(bdev->keymap[i], input->keybit);110__clear_bit(KEY_RESERVED, input->keybit);111112res = platform_get_resource(pdev, IORESOURCE_MEM, 0);113if (!res) {114error = -EBUSY;115goto err_free_mem;116}117118bdev->poll_dev = poll_dev;119bdev->reg = ioremap(res->start, resource_size(res));120dev_set_drvdata(&pdev->dev, bdev);121122error = input_register_polled_device(poll_dev);123if (error)124goto err_iounmap;125126return 0;127128err_iounmap:129iounmap(bdev->reg);130err_free_mem:131input_free_polled_device(poll_dev);132kfree(bdev);133dev_set_drvdata(&pdev->dev, NULL);134return error;135}136137static int __devexit cobalt_buttons_remove(struct platform_device *pdev)138{139struct device *dev = &pdev->dev;140struct buttons_dev *bdev = dev_get_drvdata(dev);141142input_unregister_polled_device(bdev->poll_dev);143input_free_polled_device(bdev->poll_dev);144iounmap(bdev->reg);145kfree(bdev);146dev_set_drvdata(dev, NULL);147148return 0;149}150151MODULE_AUTHOR("Yoichi Yuasa <[email protected]>");152MODULE_DESCRIPTION("Cobalt button interface driver");153MODULE_LICENSE("GPL");154/* work with hotplug and coldplug */155MODULE_ALIAS("platform:Cobalt buttons");156157static struct platform_driver cobalt_buttons_driver = {158.probe = cobalt_buttons_probe,159.remove = __devexit_p(cobalt_buttons_remove),160.driver = {161.name = "Cobalt buttons",162.owner = THIS_MODULE,163},164};165166static int __init cobalt_buttons_init(void)167{168return platform_driver_register(&cobalt_buttons_driver);169}170171static void __exit cobalt_buttons_exit(void)172{173platform_driver_unregister(&cobalt_buttons_driver);174}175176module_init(cobalt_buttons_init);177module_exit(cobalt_buttons_exit);178179180