14795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft/*
24795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * driver for powerbutton on IBM cell blades
34795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft *
44795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * (C) Copyright IBM Corp. 2005-2008
54795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft *
64795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * Author: Christian Krafft <krafft@de.ibm.com>
74795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft *
84795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * This program is free software; you can redistribute it and/or modify
94795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * it under the terms of the GNU General Public License as published by
104795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * the Free Software Foundation; either version 2, or (at your option)
114795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * any later version.
124795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft *
134795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * This program is distributed in the hope that it will be useful,
144795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * but WITHOUT ANY WARRANTY; without even the implied warranty of
154795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * GNU General Public License for more details.
174795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft *
184795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * You should have received a copy of the GNU General Public License
194795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * along with this program; if not, write to the Free Software
204795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
214795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft */
224795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
234795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft#include <linux/input.h>
247dfe293cf66258c5ef5d010f75d1f843b38e5e4aPaul Gortmaker#include <linux/module.h>
254795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft#include <linux/platform_device.h>
264795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft#include <asm/pmi.h>
274795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft#include <asm/prom.h>
284795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
294795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftstatic struct input_dev *button_dev;
304795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftstatic struct platform_device *button_pdev;
314795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
324795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftstatic void cbe_powerbutton_handle_pmi(pmi_message_t pmi_msg)
334795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft{
344795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	BUG_ON(pmi_msg.type != PMI_TYPE_POWER_BUTTON);
354795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
364795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	input_report_key(button_dev, KEY_POWER, 1);
374795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	input_sync(button_dev);
384795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	input_report_key(button_dev, KEY_POWER, 0);
394795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	input_sync(button_dev);
404795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft}
414795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
424795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftstatic struct pmi_handler cbe_pmi_handler = {
434795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	.type			= PMI_TYPE_POWER_BUTTON,
444795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	.handle_pmi_message	= cbe_powerbutton_handle_pmi,
454795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft};
464795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
474795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftstatic int __init cbe_powerbutton_init(void)
484795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft{
494795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	int ret = 0;
504795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	struct input_dev *dev;
514795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
5271a157e8edca55198e808f8561dd49017a54ee34Grant Likely	if (!of_machine_is_compatible("IBM,CBPLUS-1.0")) {
534795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		printk(KERN_ERR "%s: Not a cell blade.\n", __func__);
544795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		ret = -ENODEV;
554795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		goto out;
564795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	}
574795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
584795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	dev = input_allocate_device();
594795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	if (!dev) {
604795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		ret = -ENOMEM;
614795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		printk(KERN_ERR "%s: Not enough memory.\n", __func__);
624795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		goto out;
634795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	}
644795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
654795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	set_bit(EV_KEY, dev->evbit);
664795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	set_bit(KEY_POWER, dev->keybit);
674795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
684795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	dev->name = "Power Button";
694795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	dev->id.bustype = BUS_HOST;
704795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
714795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	/* this makes the button look like an acpi power button
724795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	 * no clue whether anyone relies on that though */
734795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	dev->id.product = 0x02;
744795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	dev->phys = "LNXPWRBN/button/input0";
754795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
764795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	button_pdev = platform_device_register_simple("power_button", 0, NULL, 0);
774795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	if (IS_ERR(button_pdev)) {
784795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		ret = PTR_ERR(button_pdev);
794795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		goto out_free_input;
804795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	}
814795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
824795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	dev->dev.parent = &button_pdev->dev;
834795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	ret = input_register_device(dev);
844795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	if (ret) {
854795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		printk(KERN_ERR "%s: Failed to register device\n", __func__);
864795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		goto out_free_pdev;
874795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	}
884795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
894795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	button_dev = dev;
904795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
914795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	ret = pmi_register_handler(&cbe_pmi_handler);
924795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	if (ret) {
934795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		printk(KERN_ERR "%s: Failed to register with pmi.\n", __func__);
944795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft		goto out_free_pdev;
954795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	}
964795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
974795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	goto out;
984795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
994795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftout_free_pdev:
1004795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	platform_device_unregister(button_pdev);
1014795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftout_free_input:
1024795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	input_free_device(dev);
1034795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftout:
1044795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	return ret;
1054795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft}
1064795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
1074795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftstatic void __exit cbe_powerbutton_exit(void)
1084795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft{
1094795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	pmi_unregister_handler(&cbe_pmi_handler);
1104795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	platform_device_unregister(button_pdev);
1114795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft	input_free_device(button_dev);
1124795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft}
1134795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
1144795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftmodule_init(cbe_powerbutton_init);
1154795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafftmodule_exit(cbe_powerbutton_exit);
1164795b7801b07e1b7286edb0d9321433fc0eac6ccChristian Krafft
1174795b7801b07e1b7286edb0d9321433fc0eac6ccChristian KrafftMODULE_LICENSE("GPL");
1184795b7801b07e1b7286edb0d9321433fc0eac6ccChristian KrafftMODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
119