Merge remote-tracking branch 'asoc/topic/tegra' into asoc-next
[deliverable/linux.git] / drivers / input / misc / sirfsoc-onkey.c
CommitLineData
9b5f953d
BD
1/*
2 * Power key driver for SiRF PrimaII
3 *
4 * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
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>
17
18struct sirfsoc_pwrc_drvdata {
19 u32 pwrc_base;
20 struct input_dev *input;
21};
22
23#define PWRC_ON_KEY_BIT (1 << 0)
24
25#define PWRC_INT_STATUS 0xc
26#define PWRC_INT_MASK 0x10
27
28static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
29{
30 struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
31 u32 int_status;
32
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);
37
38 /*
39 * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
40 * to queue a SUSPEND APM event
41 */
42 input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
43 input_sync(pwrcdrv->input);
44
45 /*
46 * Todo: report KEY_POWER event for Android platforms, Android PowerManager
47 * will handle the suspend and powerdown/hibernation
48 */
49
50 return IRQ_HANDLED;
51}
52
53static const struct of_device_id sirfsoc_pwrc_of_match[] = {
54 { .compatible = "sirf,prima2-pwrc" },
55 {},
56}
57MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
58
59static int sirfsoc_pwrc_probe(struct platform_device *pdev)
60{
61 struct device_node *np = pdev->dev.of_node;
62 struct sirfsoc_pwrc_drvdata *pwrcdrv;
63 int irq;
64 int error;
65
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;
71 }
72
73 /*
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
76 */
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;
82 }
83
84 pwrcdrv->input = devm_input_allocate_device(&pdev->dev);
85 if (!pwrcdrv->input)
86 return -ENOMEM;
87
88 pwrcdrv->input->name = "sirfsoc pwrckey";
89 pwrcdrv->input->phys = "pwrc/input0";
90 pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
91
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;
100 }
101
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);
106
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;
113 }
114
115 platform_set_drvdata(pdev, pwrcdrv);
116 device_init_wakeup(&pdev->dev, 1);
117
118 return 0;
119}
120
121static int sirfsoc_pwrc_remove(struct platform_device *pdev)
122{
123 device_init_wakeup(&pdev->dev, 0);
124
125 return 0;
126}
127
128#ifdef CONFIG_PM_SLEEP
129static int pwrc_resume(struct device *dev)
130{
131 struct platform_device *pdev = to_platform_device(dev);
132 struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev);
133
134 /*
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
137 */
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);
142
143 return 0;
144}
145#endif
146
147static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume);
148
149static 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),
157 }
158};
159
160module_platform_driver(sirfsoc_pwrc_driver);
161
162MODULE_LICENSE("GPLv2");
163MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
164MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");
165MODULE_ALIAS("platform:sirfsoc-pwrc");
This page took 0.070438 seconds and 5 git commands to generate.