Merge tag 'staging-3.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6.git] / drivers / input / misc / sirfsoc-onkey.c
blob0621c367049a3e8a0183af7f9d50611c3c0f3a11
1 /*
2 * Power key driver for SiRF PrimaII
4 * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
6 * Licensed under GPLv2 or later.
7 */
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/interrupt.h>
12 #include <linux/delay.h>
13 #include <linux/platform_device.h>
14 #include <linux/input.h>
15 #include <linux/rtc/sirfsoc_rtciobrg.h>
16 #include <linux/of.h>
18 struct sirfsoc_pwrc_drvdata {
19 u32 pwrc_base;
20 struct input_dev *input;
23 #define PWRC_ON_KEY_BIT (1 << 0)
25 #define PWRC_INT_STATUS 0xc
26 #define PWRC_INT_MASK 0x10
28 static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
30 struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
31 u32 int_status;
33 int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
34 PWRC_INT_STATUS);
35 sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
36 pwrcdrv->pwrc_base + PWRC_INT_STATUS);
39 * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
40 * to queue a SUSPEND APM event
42 input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
43 input_sync(pwrcdrv->input);
46 * Todo: report KEY_POWER event for Android platforms, Android PowerManager
47 * will handle the suspend and powerdown/hibernation
50 return IRQ_HANDLED;
53 static const struct of_device_id sirfsoc_pwrc_of_match[] = {
54 { .compatible = "sirf,prima2-pwrc" },
55 {},
57 MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
59 static int sirfsoc_pwrc_probe(struct platform_device *pdev)
61 struct device_node *np = pdev->dev.of_node;
62 struct sirfsoc_pwrc_drvdata *pwrcdrv;
63 int irq;
64 int error;
66 pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata),
67 GFP_KERNEL);
68 if (!pwrcdrv) {
69 dev_info(&pdev->dev, "Not enough memory for the device data\n");
70 return -ENOMEM;
74 * we can't use of_iomap because pwrc is not mapped in memory,
75 * the so-called base address is only offset in rtciobrg
77 error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
78 if (error) {
79 dev_err(&pdev->dev,
80 "unable to find base address of pwrc node in dtb\n");
81 return error;
84 pwrcdrv->input = devm_input_allocate_device(&pdev->dev);
85 if (!pwrcdrv->input)
86 return -ENOMEM;
88 pwrcdrv->input->name = "sirfsoc pwrckey";
89 pwrcdrv->input->phys = "pwrc/input0";
90 pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
92 irq = platform_get_irq(pdev, 0);
93 error = devm_request_irq(&pdev->dev, irq,
94 sirfsoc_pwrc_isr, IRQF_SHARED,
95 "sirfsoc_pwrc_int", pwrcdrv);
96 if (error) {
97 dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
98 irq, error);
99 return error;
102 sirfsoc_rtc_iobrg_writel(
103 sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) |
104 PWRC_ON_KEY_BIT,
105 pwrcdrv->pwrc_base + PWRC_INT_MASK);
107 error = input_register_device(pwrcdrv->input);
108 if (error) {
109 dev_err(&pdev->dev,
110 "unable to register input device, error: %d\n",
111 error);
112 return error;
115 platform_set_drvdata(pdev, pwrcdrv);
116 device_init_wakeup(&pdev->dev, 1);
118 return 0;
121 static int sirfsoc_pwrc_remove(struct platform_device *pdev)
123 device_init_wakeup(&pdev->dev, 0);
125 return 0;
128 #ifdef CONFIG_PM_SLEEP
129 static int pwrc_resume(struct device *dev)
131 struct platform_device *pdev = to_platform_device(dev);
132 struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev);
135 * Do not mask pwrc interrupt as we want pwrc work as a wakeup source
136 * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
138 sirfsoc_rtc_iobrg_writel(
139 sirfsoc_rtc_iobrg_readl(
140 pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT,
141 pwrcdrv->pwrc_base + PWRC_INT_MASK);
143 return 0;
145 #endif
147 static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume);
149 static struct platform_driver sirfsoc_pwrc_driver = {
150 .probe = sirfsoc_pwrc_probe,
151 .remove = sirfsoc_pwrc_remove,
152 .driver = {
153 .name = "sirfsoc-pwrc",
154 .owner = THIS_MODULE,
155 .pm = &sirfsoc_pwrc_pm_ops,
156 .of_match_table = of_match_ptr(sirfsoc_pwrc_of_match),
160 module_platform_driver(sirfsoc_pwrc_driver);
162 MODULE_LICENSE("GPLv2");
163 MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
164 MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");
165 MODULE_ALIAS("platform:sirfsoc-pwrc");