Commit 8eec8a1167b5912c19fec2cdad5b968dd0f8690d
Committed by
Matthew Garrett
1 parent
e2d3d44b9a
Exists in
master
and in
4 other branches
intel_mid_powerbtn: add power button driver for Medfield platform (#3)
The power button is connected to MSIC on Medfield, we will get two interrupts from IOAPIC when pressing or releasing the power button. Signed-off-by: Hong Liu <hong.liu@intel.com> [Minor fixes as noted by Dmitry] Signed-off-by: Alan Cox <alan@linux.intel.com> Acked-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Showing 3 changed files with 157 additions and 0 deletions Side-by-side Diff
drivers/platform/x86/Kconfig
... | ... | @@ -616,6 +616,14 @@ |
616 | 616 | Say Y here to support GPIO via the SCU IPC interface |
617 | 617 | on Intel MID platforms. |
618 | 618 | |
619 | +config INTEL_MID_POWER_BUTTON | |
620 | + tristate "power button driver for Intel MID platforms" | |
621 | + depends on INTEL_SCU_IPC | |
622 | + help | |
623 | + This driver handles the power button on the Intel MID platforms. | |
624 | + | |
625 | + If unsure, say N. | |
626 | + | |
619 | 627 | config RAR_REGISTER |
620 | 628 | bool "Restricted Access Region Register Driver" |
621 | 629 | depends on PCI && X86_MRST |
drivers/platform/x86/Makefile
drivers/platform/x86/intel_mid_powerbtn.c
1 | +/* | |
2 | + * Power button driver for Medfield. | |
3 | + * | |
4 | + * Copyright (C) 2010 Intel Corp | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License as published by | |
8 | + * the Free Software Foundation; version 2 of the License. | |
9 | + * | |
10 | + * This program is distributed in the hope that it will be useful, but | |
11 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | + * General Public License for more details. | |
14 | + * | |
15 | + * You should have received a copy of the GNU General Public License along | |
16 | + * with this program; if not, write to the Free Software Foundation, Inc., | |
17 | + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
18 | + */ | |
19 | + | |
20 | +#include <linux/module.h> | |
21 | +#include <linux/init.h> | |
22 | +#include <linux/interrupt.h> | |
23 | +#include <linux/slab.h> | |
24 | +#include <linux/platform_device.h> | |
25 | +#include <linux/input.h> | |
26 | +#include <asm/intel_scu_ipc.h> | |
27 | + | |
28 | +#define DRIVER_NAME "msic_power_btn" | |
29 | + | |
30 | +#define MSIC_IRQ_STAT 0x02 | |
31 | + #define MSIC_IRQ_PB (1 << 0) | |
32 | +#define MSIC_PB_CONFIG 0x3e | |
33 | +#define MSIC_PB_STATUS 0x3f | |
34 | + #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ | |
35 | + | |
36 | +struct mfld_pb_priv { | |
37 | + struct input_dev *input; | |
38 | + unsigned int irq; | |
39 | +}; | |
40 | + | |
41 | +static irqreturn_t mfld_pb_isr(int irq, void *dev_id) | |
42 | +{ | |
43 | + struct mfld_pb_priv *priv = dev_id; | |
44 | + int ret; | |
45 | + u8 pbstat; | |
46 | + | |
47 | + ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat); | |
48 | + if (ret < 0) | |
49 | + return IRQ_HANDLED; | |
50 | + | |
51 | + input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL)); | |
52 | + input_sync(priv->input); | |
53 | + | |
54 | + return IRQ_HANDLED; | |
55 | +} | |
56 | + | |
57 | +static int __devinit mfld_pb_probe(struct platform_device *pdev) | |
58 | +{ | |
59 | + struct mfld_pb_priv *priv; | |
60 | + struct input_dev *input; | |
61 | + int irq; | |
62 | + int error; | |
63 | + | |
64 | + irq = platform_get_irq(pdev, 0); | |
65 | + if (irq < 0) | |
66 | + return -EINVAL; | |
67 | + | |
68 | + priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL); | |
69 | + input = input_allocate_device(); | |
70 | + if (!priv || !input) { | |
71 | + error = -ENOMEM; | |
72 | + goto err_free_mem; | |
73 | + } | |
74 | + | |
75 | + priv->input = input; | |
76 | + priv->irq = irq; | |
77 | + | |
78 | + input->name = pdev->name; | |
79 | + input->phys = "power-button/input0"; | |
80 | + input->id.bustype = BUS_HOST; | |
81 | + input->dev.parent = &pdev->dev; | |
82 | + | |
83 | + input_set_capability(input, EV_KEY, KEY_POWER); | |
84 | + | |
85 | + error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr, | |
86 | + 0, DRIVER_NAME, priv); | |
87 | + if (error) { | |
88 | + dev_err(&pdev->dev, | |
89 | + "unable to request irq %d for mfld power button\n", | |
90 | + irq); | |
91 | + goto err_free_mem; | |
92 | + } | |
93 | + | |
94 | + error = input_register_device(input); | |
95 | + if (error) { | |
96 | + dev_err(&pdev->dev, | |
97 | + "unable to register input dev, error %d\n", error); | |
98 | + goto err_free_irq; | |
99 | + } | |
100 | + | |
101 | + platform_set_drvdata(pdev, priv); | |
102 | + return 0; | |
103 | + | |
104 | +err_free_irq: | |
105 | + free_irq(priv->irq, priv); | |
106 | +err_free_mem: | |
107 | + input_free_device(input); | |
108 | + kfree(priv); | |
109 | + return error; | |
110 | +} | |
111 | + | |
112 | +static int __devexit mfld_pb_remove(struct platform_device *pdev) | |
113 | +{ | |
114 | + struct mfld_pb_priv *priv = platform_get_drvdata(pdev); | |
115 | + | |
116 | + free_irq(priv->irq, priv); | |
117 | + input_unregister_device(priv->input); | |
118 | + kfree(priv); | |
119 | + | |
120 | + platform_set_drvdata(pdev, NULL); | |
121 | + return 0; | |
122 | +} | |
123 | + | |
124 | +static struct platform_driver mfld_pb_driver = { | |
125 | + .driver = { | |
126 | + .name = DRIVER_NAME, | |
127 | + .owner = THIS_MODULE, | |
128 | + }, | |
129 | + .probe = mfld_pb_probe, | |
130 | + .remove = __devexit_p(mfld_pb_remove), | |
131 | +}; | |
132 | + | |
133 | +static int __init mfld_pb_init(void) | |
134 | +{ | |
135 | + return platform_driver_register(&mfld_pb_driver); | |
136 | +} | |
137 | +module_init(mfld_pb_init); | |
138 | + | |
139 | +static void __exit mfld_pb_exit(void) | |
140 | +{ | |
141 | + platform_driver_unregister(&mfld_pb_driver); | |
142 | +} | |
143 | +module_exit(mfld_pb_exit); | |
144 | + | |
145 | +MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>"); | |
146 | +MODULE_DESCRIPTION("Intel Medfield Power Button Driver"); | |
147 | +MODULE_LICENSE("GPL v2"); | |
148 | +MODULE_ALIAS("platform:" DRIVER_NAME); |