diff options
Diffstat (limited to 'drivers/input/misc/cobalt_btns.c')
-rw-r--r-- | drivers/input/misc/cobalt_btns.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c new file mode 100644 index 000000000..b1624f541 --- /dev/null +++ b/drivers/input/misc/cobalt_btns.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Cobalt button interface driver. + * + * Copyright (C) 2007-2008 Yoichi Yuasa <yuasa@linux-mips.org> + */ +#include <linux/input.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define BUTTONS_POLL_INTERVAL 30 /* msec */ +#define BUTTONS_COUNT_THRESHOLD 3 +#define BUTTONS_STATUS_MASK 0xfe000000 + +static const unsigned short cobalt_map[] = { + KEY_RESERVED, + KEY_RESTART, + KEY_LEFT, + KEY_UP, + KEY_DOWN, + KEY_RIGHT, + KEY_ENTER, + KEY_SELECT +}; + +struct buttons_dev { + unsigned short keymap[ARRAY_SIZE(cobalt_map)]; + int count[ARRAY_SIZE(cobalt_map)]; + void __iomem *reg; +}; + +static void handle_buttons(struct input_dev *input) +{ + struct buttons_dev *bdev = input_get_drvdata(input); + uint32_t status; + int i; + + status = ~readl(bdev->reg) >> 24; + + for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) { + if (status & (1U << i)) { + if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) { + input_event(input, EV_MSC, MSC_SCAN, i); + input_report_key(input, bdev->keymap[i], 1); + input_sync(input); + } + } else { + if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) { + input_event(input, EV_MSC, MSC_SCAN, i); + input_report_key(input, bdev->keymap[i], 0); + input_sync(input); + } + bdev->count[i] = 0; + } + } +} + +static int cobalt_buttons_probe(struct platform_device *pdev) +{ + struct buttons_dev *bdev; + struct input_dev *input; + struct resource *res; + int error, i; + + bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL); + if (!bdev) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EBUSY; + + bdev->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!bdev->reg) + return -ENOMEM; + + memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap)); + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; + + input_set_drvdata(input, bdev); + + input->name = "Cobalt buttons"; + input->phys = "cobalt/input0"; + input->id.bustype = BUS_HOST; + + input->keycode = bdev->keymap; + input->keycodemax = ARRAY_SIZE(bdev->keymap); + input->keycodesize = sizeof(unsigned short); + + input_set_capability(input, EV_MSC, MSC_SCAN); + __set_bit(EV_KEY, input->evbit); + for (i = 0; i < ARRAY_SIZE(cobalt_map); i++) + __set_bit(bdev->keymap[i], input->keybit); + __clear_bit(KEY_RESERVED, input->keybit); + + + error = input_setup_polling(input, handle_buttons); + if (error) + return error; + + input_set_poll_interval(input, BUTTONS_POLL_INTERVAL); + + error = input_register_device(input); + if (error) + return error; + + return 0; +} + +MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); +MODULE_DESCRIPTION("Cobalt button interface driver"); +MODULE_LICENSE("GPL"); +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:Cobalt buttons"); + +static struct platform_driver cobalt_buttons_driver = { + .probe = cobalt_buttons_probe, + .driver = { + .name = "Cobalt buttons", + }, +}; +module_platform_driver(cobalt_buttons_driver); |