1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * driver for powerbutton on IBM cell blades |
4 | * |
5 | * (C) Copyright IBM Corp. 2005-2008 |
6 | * |
7 | * Author: Christian Krafft <krafft@de.ibm.com> |
8 | */ |
9 | |
10 | #include <linux/input.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of.h> |
13 | #include <linux/platform_device.h> |
14 | #include <asm/pmi.h> |
15 | |
16 | static struct input_dev *button_dev; |
17 | static struct platform_device *button_pdev; |
18 | |
19 | static void cbe_powerbutton_handle_pmi(pmi_message_t pmi_msg) |
20 | { |
21 | BUG_ON(pmi_msg.type != PMI_TYPE_POWER_BUTTON); |
22 | |
23 | input_report_key(dev: button_dev, KEY_POWER, value: 1); |
24 | input_sync(dev: button_dev); |
25 | input_report_key(dev: button_dev, KEY_POWER, value: 0); |
26 | input_sync(dev: button_dev); |
27 | } |
28 | |
29 | static struct pmi_handler cbe_pmi_handler = { |
30 | .type = PMI_TYPE_POWER_BUTTON, |
31 | .handle_pmi_message = cbe_powerbutton_handle_pmi, |
32 | }; |
33 | |
34 | static int __init cbe_powerbutton_init(void) |
35 | { |
36 | int ret = 0; |
37 | struct input_dev *dev; |
38 | |
39 | if (!of_machine_is_compatible(compat: "IBM,CBPLUS-1.0" )) { |
40 | printk(KERN_ERR "%s: Not a cell blade.\n" , __func__); |
41 | ret = -ENODEV; |
42 | goto out; |
43 | } |
44 | |
45 | dev = input_allocate_device(); |
46 | if (!dev) { |
47 | ret = -ENOMEM; |
48 | printk(KERN_ERR "%s: Not enough memory.\n" , __func__); |
49 | goto out; |
50 | } |
51 | |
52 | set_bit(EV_KEY, addr: dev->evbit); |
53 | set_bit(KEY_POWER, addr: dev->keybit); |
54 | |
55 | dev->name = "Power Button" ; |
56 | dev->id.bustype = BUS_HOST; |
57 | |
58 | /* this makes the button look like an acpi power button |
59 | * no clue whether anyone relies on that though */ |
60 | dev->id.product = 0x02; |
61 | dev->phys = "LNXPWRBN/button/input0" ; |
62 | |
63 | button_pdev = platform_device_register_simple(name: "power_button" , id: 0, NULL, num: 0); |
64 | if (IS_ERR(ptr: button_pdev)) { |
65 | ret = PTR_ERR(ptr: button_pdev); |
66 | goto out_free_input; |
67 | } |
68 | |
69 | dev->dev.parent = &button_pdev->dev; |
70 | ret = input_register_device(dev); |
71 | if (ret) { |
72 | printk(KERN_ERR "%s: Failed to register device\n" , __func__); |
73 | goto out_free_pdev; |
74 | } |
75 | |
76 | button_dev = dev; |
77 | |
78 | ret = pmi_register_handler(&cbe_pmi_handler); |
79 | if (ret) { |
80 | printk(KERN_ERR "%s: Failed to register with pmi.\n" , __func__); |
81 | goto out_free_pdev; |
82 | } |
83 | |
84 | goto out; |
85 | |
86 | out_free_pdev: |
87 | platform_device_unregister(button_pdev); |
88 | out_free_input: |
89 | input_free_device(dev); |
90 | out: |
91 | return ret; |
92 | } |
93 | |
94 | static void __exit cbe_powerbutton_exit(void) |
95 | { |
96 | pmi_unregister_handler(&cbe_pmi_handler); |
97 | platform_device_unregister(button_pdev); |
98 | input_free_device(dev: button_dev); |
99 | } |
100 | |
101 | module_init(cbe_powerbutton_init); |
102 | module_exit(cbe_powerbutton_exit); |
103 | |
104 | MODULE_LICENSE("GPL" ); |
105 | MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>" ); |
106 | |