xref: /openbmc/linux/drivers/input/misc/cobalt_btns.c (revision 4d69ca90)
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  */
73d29cdffSDmitry Torokhov #include <linux/input-polldev.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 
353d29cdffSDmitry Torokhov static void handle_buttons(struct input_polled_dev *dev)
36bebb8a2bSYoichi Yuasa {
373d29cdffSDmitry Torokhov 	struct buttons_dev *bdev = dev->private;
383d29cdffSDmitry Torokhov 	struct input_dev *input = dev->input;
39bebb8a2bSYoichi Yuasa 	uint32_t status;
40bebb8a2bSYoichi Yuasa 	int i;
41bebb8a2bSYoichi Yuasa 
42b037b08eSDmitry Torokhov 	status = ~readl(bdev->reg) >> 24;
43bebb8a2bSYoichi Yuasa 
44b037b08eSDmitry Torokhov 	for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) {
453c514387SYoichi Yuasa 		if (status & (1U << i)) {
46b037b08eSDmitry Torokhov 			if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) {
47b037b08eSDmitry Torokhov 				input_event(input, EV_MSC, MSC_SCAN, i);
48b037b08eSDmitry Torokhov 				input_report_key(input, bdev->keymap[i], 1);
49b037b08eSDmitry Torokhov 				input_sync(input);
50b037b08eSDmitry Torokhov 			}
51bebb8a2bSYoichi Yuasa 		} else {
52b037b08eSDmitry Torokhov 			if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) {
53b037b08eSDmitry Torokhov 				input_event(input, EV_MSC, MSC_SCAN, i);
54b037b08eSDmitry Torokhov 				input_report_key(input, bdev->keymap[i], 0);
553d29cdffSDmitry Torokhov 				input_sync(input);
56bebb8a2bSYoichi Yuasa 			}
57b037b08eSDmitry Torokhov 			bdev->count[i] = 0;
58bebb8a2bSYoichi Yuasa 		}
59bebb8a2bSYoichi Yuasa 	}
60bebb8a2bSYoichi Yuasa }
61bebb8a2bSYoichi Yuasa 
625298cc4cSBill Pemberton static int cobalt_buttons_probe(struct platform_device *pdev)
63bebb8a2bSYoichi Yuasa {
64bebb8a2bSYoichi Yuasa 	struct buttons_dev *bdev;
653d29cdffSDmitry Torokhov 	struct input_polled_dev *poll_dev;
66bebb8a2bSYoichi Yuasa 	struct input_dev *input;
67bebb8a2bSYoichi Yuasa 	struct resource *res;
68bebb8a2bSYoichi Yuasa 	int error, i;
69bebb8a2bSYoichi Yuasa 
704d69ca90SDmitry Torokhov 	bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
714d69ca90SDmitry Torokhov 	if (!bdev)
724d69ca90SDmitry Torokhov 		return -ENOMEM;
734d69ca90SDmitry Torokhov 
744d69ca90SDmitry Torokhov 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
754d69ca90SDmitry Torokhov 	if (!res)
764d69ca90SDmitry Torokhov 		return -EBUSY;
774d69ca90SDmitry Torokhov 
784d69ca90SDmitry Torokhov 	bdev->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
794d69ca90SDmitry Torokhov 	if (!bdev->reg)
804d69ca90SDmitry Torokhov 		return -ENOMEM;
81bebb8a2bSYoichi Yuasa 
82b037b08eSDmitry Torokhov 	memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap));
83b037b08eSDmitry Torokhov 
844d69ca90SDmitry Torokhov 	poll_dev = devm_input_allocate_polled_device(&pdev->dev);
854d69ca90SDmitry Torokhov 	if (!poll_dev)
864d69ca90SDmitry Torokhov 		return -ENOMEM;
874d69ca90SDmitry Torokhov 
883d29cdffSDmitry Torokhov 	poll_dev->private = bdev;
893d29cdffSDmitry Torokhov 	poll_dev->poll = handle_buttons;
903d29cdffSDmitry Torokhov 	poll_dev->poll_interval = BUTTONS_POLL_INTERVAL;
913d29cdffSDmitry Torokhov 
923d29cdffSDmitry Torokhov 	input = poll_dev->input;
93bebb8a2bSYoichi Yuasa 	input->name = "Cobalt buttons";
94bebb8a2bSYoichi Yuasa 	input->phys = "cobalt/input0";
95bebb8a2bSYoichi Yuasa 	input->id.bustype = BUS_HOST;
96bebb8a2bSYoichi Yuasa 
973c514387SYoichi Yuasa 	input->keycode = bdev->keymap;
983c514387SYoichi Yuasa 	input->keycodemax = ARRAY_SIZE(bdev->keymap);
99b037b08eSDmitry Torokhov 	input->keycodesize = sizeof(unsigned short);
100b037b08eSDmitry Torokhov 
101b037b08eSDmitry Torokhov 	input_set_capability(input, EV_MSC, MSC_SCAN);
102b037b08eSDmitry Torokhov 	__set_bit(EV_KEY, input->evbit);
1033c514387SYoichi Yuasa 	for (i = 0; i < ARRAY_SIZE(cobalt_map); i++)
1043c514387SYoichi Yuasa 		__set_bit(bdev->keymap[i], input->keybit);
105b037b08eSDmitry Torokhov 	__clear_bit(KEY_RESERVED, input->keybit);
106bebb8a2bSYoichi Yuasa 
1073d29cdffSDmitry Torokhov 	error = input_register_polled_device(poll_dev);
108bebb8a2bSYoichi Yuasa 	if (error)
109bebb8a2bSYoichi Yuasa 		return error;
110bebb8a2bSYoichi Yuasa 
111bebb8a2bSYoichi Yuasa 	return 0;
112bebb8a2bSYoichi Yuasa }
113bebb8a2bSYoichi Yuasa 
114ada8e951SYoichi Yuasa MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
11526135ed3SMartin Michlmayr MODULE_DESCRIPTION("Cobalt button interface driver");
11626135ed3SMartin Michlmayr MODULE_LICENSE("GPL");
117d7b5247bSKay Sievers /* work with hotplug and coldplug */
118d7b5247bSKay Sievers MODULE_ALIAS("platform:Cobalt buttons");
119d7b5247bSKay Sievers 
120bebb8a2bSYoichi Yuasa static struct platform_driver cobalt_buttons_driver = {
121bebb8a2bSYoichi Yuasa 	.probe	= cobalt_buttons_probe,
122bebb8a2bSYoichi Yuasa 	.driver	= {
123bebb8a2bSYoichi Yuasa 		.name	= "Cobalt buttons",
124bebb8a2bSYoichi Yuasa 	},
125bebb8a2bSYoichi Yuasa };
126840a746bSJJ Ding module_platform_driver(cobalt_buttons_driver);
127