xref: /openbmc/linux/drivers/input/misc/cobalt_btns.c (revision 5d96738d)
116216333SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2bebb8a2bSYoichi Yuasa /*
3bebb8a2bSYoichi Yuasa  *  Cobalt button interface driver.
4bebb8a2bSYoichi Yuasa  *
5ada8e951SYoichi Yuasa  *  Copyright (C) 2007-2008  Yoichi Yuasa <yuasa@linux-mips.org>
6bebb8a2bSYoichi Yuasa  */
75d96738dSDmitry Torokhov #include <linux/input.h>
84d69ca90SDmitry Torokhov #include <linux/io.h>
9bebb8a2bSYoichi Yuasa #include <linux/ioport.h>
10bebb8a2bSYoichi Yuasa #include <linux/module.h>
11bebb8a2bSYoichi Yuasa #include <linux/platform_device.h>
125a0e3ad6STejun Heo #include <linux/slab.h>
13bebb8a2bSYoichi Yuasa 
14bebb8a2bSYoichi Yuasa #define BUTTONS_POLL_INTERVAL	30	/* msec */
15bebb8a2bSYoichi Yuasa #define BUTTONS_COUNT_THRESHOLD	3
16bebb8a2bSYoichi Yuasa #define BUTTONS_STATUS_MASK	0xfe000000
17bebb8a2bSYoichi Yuasa 
18b037b08eSDmitry Torokhov static const unsigned short cobalt_map[] = {
19b037b08eSDmitry Torokhov 	KEY_RESERVED,
20b037b08eSDmitry Torokhov 	KEY_RESTART,
21b037b08eSDmitry Torokhov 	KEY_LEFT,
22b037b08eSDmitry Torokhov 	KEY_UP,
23b037b08eSDmitry Torokhov 	KEY_DOWN,
24b037b08eSDmitry Torokhov 	KEY_RIGHT,
25b037b08eSDmitry Torokhov 	KEY_ENTER,
26b037b08eSDmitry Torokhov 	KEY_SELECT
27b037b08eSDmitry Torokhov };
28b037b08eSDmitry Torokhov 
29bebb8a2bSYoichi Yuasa struct buttons_dev {
30b037b08eSDmitry Torokhov 	unsigned short keymap[ARRAY_SIZE(cobalt_map)];
31b037b08eSDmitry Torokhov 	int count[ARRAY_SIZE(cobalt_map)];
32bebb8a2bSYoichi Yuasa 	void __iomem *reg;
33bebb8a2bSYoichi Yuasa };
34bebb8a2bSYoichi Yuasa 
handle_buttons(struct input_dev * input)355d96738dSDmitry Torokhov static void handle_buttons(struct input_dev *input)
36bebb8a2bSYoichi Yuasa {
375d96738dSDmitry Torokhov 	struct buttons_dev *bdev = input_get_drvdata(input);
38bebb8a2bSYoichi Yuasa 	uint32_t status;
39bebb8a2bSYoichi Yuasa 	int i;
40bebb8a2bSYoichi Yuasa 
41b037b08eSDmitry Torokhov 	status = ~readl(bdev->reg) >> 24;
42bebb8a2bSYoichi Yuasa 
43b037b08eSDmitry Torokhov 	for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) {
443c514387SYoichi Yuasa 		if (status & (1U << i)) {
45b037b08eSDmitry Torokhov 			if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) {
46b037b08eSDmitry Torokhov 				input_event(input, EV_MSC, MSC_SCAN, i);
47b037b08eSDmitry Torokhov 				input_report_key(input, bdev->keymap[i], 1);
48b037b08eSDmitry Torokhov 				input_sync(input);
49b037b08eSDmitry Torokhov 			}
50bebb8a2bSYoichi Yuasa 		} else {
51b037b08eSDmitry Torokhov 			if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) {
52b037b08eSDmitry Torokhov 				input_event(input, EV_MSC, MSC_SCAN, i);
53b037b08eSDmitry Torokhov 				input_report_key(input, bdev->keymap[i], 0);
543d29cdffSDmitry Torokhov 				input_sync(input);
55bebb8a2bSYoichi Yuasa 			}
56b037b08eSDmitry Torokhov 			bdev->count[i] = 0;
57bebb8a2bSYoichi Yuasa 		}
58bebb8a2bSYoichi Yuasa 	}
59bebb8a2bSYoichi Yuasa }
60bebb8a2bSYoichi Yuasa 
cobalt_buttons_probe(struct platform_device * pdev)615298cc4cSBill Pemberton static int cobalt_buttons_probe(struct platform_device *pdev)
62bebb8a2bSYoichi Yuasa {
63bebb8a2bSYoichi Yuasa 	struct buttons_dev *bdev;
64bebb8a2bSYoichi Yuasa 	struct input_dev *input;
65bebb8a2bSYoichi Yuasa 	struct resource *res;
66bebb8a2bSYoichi Yuasa 	int error, i;
67bebb8a2bSYoichi Yuasa 
684d69ca90SDmitry Torokhov 	bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
694d69ca90SDmitry Torokhov 	if (!bdev)
704d69ca90SDmitry Torokhov 		return -ENOMEM;
714d69ca90SDmitry Torokhov 
724d69ca90SDmitry Torokhov 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
734d69ca90SDmitry Torokhov 	if (!res)
744d69ca90SDmitry Torokhov 		return -EBUSY;
754d69ca90SDmitry Torokhov 
764d69ca90SDmitry Torokhov 	bdev->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
774d69ca90SDmitry Torokhov 	if (!bdev->reg)
784d69ca90SDmitry Torokhov 		return -ENOMEM;
79bebb8a2bSYoichi Yuasa 
80b037b08eSDmitry Torokhov 	memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap));
81b037b08eSDmitry Torokhov 
825d96738dSDmitry Torokhov 	input = devm_input_allocate_device(&pdev->dev);
835d96738dSDmitry Torokhov 	if (!input)
844d69ca90SDmitry Torokhov 		return -ENOMEM;
854d69ca90SDmitry Torokhov 
865d96738dSDmitry Torokhov 	input_set_drvdata(input, bdev);
873d29cdffSDmitry Torokhov 
88bebb8a2bSYoichi Yuasa 	input->name = "Cobalt buttons";
89bebb8a2bSYoichi Yuasa 	input->phys = "cobalt/input0";
90bebb8a2bSYoichi Yuasa 	input->id.bustype = BUS_HOST;
91bebb8a2bSYoichi Yuasa 
923c514387SYoichi Yuasa 	input->keycode = bdev->keymap;
933c514387SYoichi Yuasa 	input->keycodemax = ARRAY_SIZE(bdev->keymap);
94b037b08eSDmitry Torokhov 	input->keycodesize = sizeof(unsigned short);
95b037b08eSDmitry Torokhov 
96b037b08eSDmitry Torokhov 	input_set_capability(input, EV_MSC, MSC_SCAN);
97b037b08eSDmitry Torokhov 	__set_bit(EV_KEY, input->evbit);
983c514387SYoichi Yuasa 	for (i = 0; i < ARRAY_SIZE(cobalt_map); i++)
993c514387SYoichi Yuasa 		__set_bit(bdev->keymap[i], input->keybit);
100b037b08eSDmitry Torokhov 	__clear_bit(KEY_RESERVED, input->keybit);
101bebb8a2bSYoichi Yuasa 
1025d96738dSDmitry Torokhov 
1035d96738dSDmitry Torokhov 	error = input_setup_polling(input, handle_buttons);
1045d96738dSDmitry Torokhov 	if (error)
1055d96738dSDmitry Torokhov 		return error;
1065d96738dSDmitry Torokhov 
1075d96738dSDmitry Torokhov 	input_set_poll_interval(input, BUTTONS_POLL_INTERVAL);
1085d96738dSDmitry Torokhov 
1095d96738dSDmitry Torokhov 	error = input_register_device(input);
110bebb8a2bSYoichi Yuasa 	if (error)
111bebb8a2bSYoichi Yuasa 		return error;
112bebb8a2bSYoichi Yuasa 
113bebb8a2bSYoichi Yuasa 	return 0;
114bebb8a2bSYoichi Yuasa }
115bebb8a2bSYoichi Yuasa 
116ada8e951SYoichi Yuasa MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
11726135ed3SMartin Michlmayr MODULE_DESCRIPTION("Cobalt button interface driver");
11826135ed3SMartin Michlmayr MODULE_LICENSE("GPL");
119d7b5247bSKay Sievers /* work with hotplug and coldplug */
120d7b5247bSKay Sievers MODULE_ALIAS("platform:Cobalt buttons");
121d7b5247bSKay Sievers 
122bebb8a2bSYoichi Yuasa static struct platform_driver cobalt_buttons_driver = {
123bebb8a2bSYoichi Yuasa 	.probe	= cobalt_buttons_probe,
124bebb8a2bSYoichi Yuasa 	.driver	= {
125bebb8a2bSYoichi Yuasa 		.name	= "Cobalt buttons",
126bebb8a2bSYoichi Yuasa 	},
127bebb8a2bSYoichi Yuasa };
128840a746bSJJ Ding module_platform_driver(cobalt_buttons_driver);
129