xref: /openbmc/linux/drivers/input/misc/cobalt_btns.c (revision c95baf12f5077419db01313ab61c2aac007d40cd)
1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   *  Cobalt button interface driver.
4   *
5   *  Copyright (C) 2007-2008  Yoichi Yuasa <yuasa@linux-mips.org>
6   */
7  #include <linux/input.h>
8  #include <linux/io.h>
9  #include <linux/ioport.h>
10  #include <linux/module.h>
11  #include <linux/platform_device.h>
12  #include <linux/slab.h>
13  
14  #define BUTTONS_POLL_INTERVAL	30	/* msec */
15  #define BUTTONS_COUNT_THRESHOLD	3
16  #define BUTTONS_STATUS_MASK	0xfe000000
17  
18  static const unsigned short cobalt_map[] = {
19  	KEY_RESERVED,
20  	KEY_RESTART,
21  	KEY_LEFT,
22  	KEY_UP,
23  	KEY_DOWN,
24  	KEY_RIGHT,
25  	KEY_ENTER,
26  	KEY_SELECT
27  };
28  
29  struct buttons_dev {
30  	unsigned short keymap[ARRAY_SIZE(cobalt_map)];
31  	int count[ARRAY_SIZE(cobalt_map)];
32  	void __iomem *reg;
33  };
34  
handle_buttons(struct input_dev * input)35  static void handle_buttons(struct input_dev *input)
36  {
37  	struct buttons_dev *bdev = input_get_drvdata(input);
38  	uint32_t status;
39  	int i;
40  
41  	status = ~readl(bdev->reg) >> 24;
42  
43  	for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) {
44  		if (status & (1U << i)) {
45  			if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) {
46  				input_event(input, EV_MSC, MSC_SCAN, i);
47  				input_report_key(input, bdev->keymap[i], 1);
48  				input_sync(input);
49  			}
50  		} else {
51  			if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) {
52  				input_event(input, EV_MSC, MSC_SCAN, i);
53  				input_report_key(input, bdev->keymap[i], 0);
54  				input_sync(input);
55  			}
56  			bdev->count[i] = 0;
57  		}
58  	}
59  }
60  
cobalt_buttons_probe(struct platform_device * pdev)61  static int cobalt_buttons_probe(struct platform_device *pdev)
62  {
63  	struct buttons_dev *bdev;
64  	struct input_dev *input;
65  	struct resource *res;
66  	int error, i;
67  
68  	bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
69  	if (!bdev)
70  		return -ENOMEM;
71  
72  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
73  	if (!res)
74  		return -EBUSY;
75  
76  	bdev->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
77  	if (!bdev->reg)
78  		return -ENOMEM;
79  
80  	memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap));
81  
82  	input = devm_input_allocate_device(&pdev->dev);
83  	if (!input)
84  		return -ENOMEM;
85  
86  	input_set_drvdata(input, bdev);
87  
88  	input->name = "Cobalt buttons";
89  	input->phys = "cobalt/input0";
90  	input->id.bustype = BUS_HOST;
91  
92  	input->keycode = bdev->keymap;
93  	input->keycodemax = ARRAY_SIZE(bdev->keymap);
94  	input->keycodesize = sizeof(unsigned short);
95  
96  	input_set_capability(input, EV_MSC, MSC_SCAN);
97  	__set_bit(EV_KEY, input->evbit);
98  	for (i = 0; i < ARRAY_SIZE(cobalt_map); i++)
99  		__set_bit(bdev->keymap[i], input->keybit);
100  	__clear_bit(KEY_RESERVED, input->keybit);
101  
102  
103  	error = input_setup_polling(input, handle_buttons);
104  	if (error)
105  		return error;
106  
107  	input_set_poll_interval(input, BUTTONS_POLL_INTERVAL);
108  
109  	error = input_register_device(input);
110  	if (error)
111  		return error;
112  
113  	return 0;
114  }
115  
116  MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
117  MODULE_DESCRIPTION("Cobalt button interface driver");
118  MODULE_LICENSE("GPL");
119  /* work with hotplug and coldplug */
120  MODULE_ALIAS("platform:Cobalt buttons");
121  
122  static struct platform_driver cobalt_buttons_driver = {
123  	.probe	= cobalt_buttons_probe,
124  	.driver	= {
125  		.name	= "Cobalt buttons",
126  	},
127  };
128  module_platform_driver(cobalt_buttons_driver);
129