2 * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
3 * Copyright (c) 2014, Sony Mobile Communications Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <linux/delay.h>
16 #include <linux/errno.h>
17 #include <linux/input.h>
18 #include <linux/interrupt.h>
19 #include <linux/kernel.h>
20 #include <linux/log2.h>
21 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 #include <linux/reboot.h>
25 #include <linux/regmap.h>
29 #define PON_RT_STS 0x10
30 #define PON_KPDPWR_N_SET BIT(0)
32 #define PON_PS_HOLD_RST_CTL 0x5a
33 #define PON_PS_HOLD_RST_CTL2 0x5b
34 #define PON_PS_HOLD_ENABLE BIT(7)
35 #define PON_PS_HOLD_TYPE_MASK 0x0f
36 #define PON_PS_HOLD_TYPE_SHUTDOWN 4
37 #define PON_PS_HOLD_TYPE_HARD_RESET 7
39 #define PON_PULL_CTL 0x70
40 #define PON_KPDPWR_PULL_UP BIT(1)
42 #define PON_DBC_CTL 0x71
43 #define PON_DBC_DELAY_MASK 0x7
46 struct pm8941_pwrkey
{
50 struct regmap
*regmap
;
51 struct input_dev
*input
;
53 unsigned int revision
;
54 struct notifier_block reboot_notifier
;
57 static int pm8941_reboot_notify(struct notifier_block
*nb
,
58 unsigned long code
, void *unused
)
60 struct pm8941_pwrkey
*pwrkey
= container_of(nb
, struct pm8941_pwrkey
,
62 unsigned int enable_reg
;
63 unsigned int reset_type
;
66 /* PMICs with revision 0 have the enable bit in same register as ctrl */
67 if (pwrkey
->revision
== 0)
68 enable_reg
= PON_PS_HOLD_RST_CTL
;
70 enable_reg
= PON_PS_HOLD_RST_CTL2
;
72 error
= regmap_update_bits(pwrkey
->regmap
,
73 pwrkey
->baseaddr
+ enable_reg
,
78 "unable to clear ps hold reset enable: %d\n",
82 * Updates of PON_PS_HOLD_ENABLE requires 3 sleep cycles between
85 usleep_range(100, 1000);
90 reset_type
= PON_PS_HOLD_TYPE_SHUTDOWN
;
94 reset_type
= PON_PS_HOLD_TYPE_HARD_RESET
;
98 error
= regmap_update_bits(pwrkey
->regmap
,
99 pwrkey
->baseaddr
+ PON_PS_HOLD_RST_CTL
,
100 PON_PS_HOLD_TYPE_MASK
,
103 dev_err(pwrkey
->dev
, "unable to set ps hold reset type: %d\n",
106 error
= regmap_update_bits(pwrkey
->regmap
,
107 pwrkey
->baseaddr
+ enable_reg
,
111 dev_err(pwrkey
->dev
, "unable to re-set enable: %d\n", error
);
116 static irqreturn_t
pm8941_pwrkey_irq(int irq
, void *_data
)
118 struct pm8941_pwrkey
*pwrkey
= _data
;
122 error
= regmap_read(pwrkey
->regmap
,
123 pwrkey
->baseaddr
+ PON_RT_STS
, &sts
);
127 input_report_key(pwrkey
->input
, KEY_POWER
, !!(sts
& PON_KPDPWR_N_SET
));
128 input_sync(pwrkey
->input
);
133 static int __maybe_unused
pm8941_pwrkey_suspend(struct device
*dev
)
135 struct pm8941_pwrkey
*pwrkey
= dev_get_drvdata(dev
);
137 if (device_may_wakeup(dev
))
138 enable_irq_wake(pwrkey
->irq
);
143 static int __maybe_unused
pm8941_pwrkey_resume(struct device
*dev
)
145 struct pm8941_pwrkey
*pwrkey
= dev_get_drvdata(dev
);
147 if (device_may_wakeup(dev
))
148 disable_irq_wake(pwrkey
->irq
);
153 static SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops
,
154 pm8941_pwrkey_suspend
, pm8941_pwrkey_resume
);
156 static int pm8941_pwrkey_probe(struct platform_device
*pdev
)
158 struct pm8941_pwrkey
*pwrkey
;
163 if (of_property_read_u32(pdev
->dev
.of_node
, "debounce", &req_delay
))
166 if (req_delay
> 2000000 || req_delay
== 0) {
167 dev_err(&pdev
->dev
, "invalid debounce time: %u\n", req_delay
);
171 pull_up
= of_property_read_bool(pdev
->dev
.of_node
, "bias-pull-up");
173 pwrkey
= devm_kzalloc(&pdev
->dev
, sizeof(*pwrkey
), GFP_KERNEL
);
177 pwrkey
->dev
= &pdev
->dev
;
179 pwrkey
->regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
180 if (!pwrkey
->regmap
) {
181 dev_err(&pdev
->dev
, "failed to locate regmap\n");
185 pwrkey
->irq
= platform_get_irq(pdev
, 0);
186 if (pwrkey
->irq
< 0) {
187 dev_err(&pdev
->dev
, "failed to get irq\n");
191 error
= of_property_read_u32(pdev
->dev
.of_node
, "reg",
196 error
= regmap_read(pwrkey
->regmap
, pwrkey
->baseaddr
+ PON_REV2
,
199 dev_err(&pdev
->dev
, "failed to set debounce: %d\n", error
);
203 pwrkey
->input
= devm_input_allocate_device(&pdev
->dev
);
204 if (!pwrkey
->input
) {
205 dev_dbg(&pdev
->dev
, "unable to allocate input device\n");
209 input_set_capability(pwrkey
->input
, EV_KEY
, KEY_POWER
);
211 pwrkey
->input
->name
= "pm8941_pwrkey";
212 pwrkey
->input
->phys
= "pm8941_pwrkey/input0";
214 req_delay
= (req_delay
<< 6) / USEC_PER_SEC
;
215 req_delay
= ilog2(req_delay
);
217 error
= regmap_update_bits(pwrkey
->regmap
,
218 pwrkey
->baseaddr
+ PON_DBC_CTL
,
222 dev_err(&pdev
->dev
, "failed to set debounce: %d\n", error
);
226 error
= regmap_update_bits(pwrkey
->regmap
,
227 pwrkey
->baseaddr
+ PON_PULL_CTL
,
229 pull_up
? PON_KPDPWR_PULL_UP
: 0);
231 dev_err(&pdev
->dev
, "failed to set pull: %d\n", error
);
235 error
= devm_request_threaded_irq(&pdev
->dev
, pwrkey
->irq
,
236 NULL
, pm8941_pwrkey_irq
,
238 "pm8941_pwrkey", pwrkey
);
240 dev_err(&pdev
->dev
, "failed requesting IRQ: %d\n", error
);
244 error
= input_register_device(pwrkey
->input
);
246 dev_err(&pdev
->dev
, "failed to register input device: %d\n",
251 pwrkey
->reboot_notifier
.notifier_call
= pm8941_reboot_notify
,
252 error
= register_reboot_notifier(&pwrkey
->reboot_notifier
);
254 dev_err(&pdev
->dev
, "failed to register reboot notifier: %d\n",
259 platform_set_drvdata(pdev
, pwrkey
);
260 device_init_wakeup(&pdev
->dev
, 1);
265 static int pm8941_pwrkey_remove(struct platform_device
*pdev
)
267 struct pm8941_pwrkey
*pwrkey
= platform_get_drvdata(pdev
);
269 unregister_reboot_notifier(&pwrkey
->reboot_notifier
);
274 static const struct of_device_id pm8941_pwr_key_id_table
[] = {
275 { .compatible
= "qcom,pm8941-pwrkey" },
278 MODULE_DEVICE_TABLE(of
, pm8941_pwr_key_id_table
);
280 static struct platform_driver pm8941_pwrkey_driver
= {
281 .probe
= pm8941_pwrkey_probe
,
282 .remove
= pm8941_pwrkey_remove
,
284 .name
= "pm8941-pwrkey",
285 .pm
= &pm8941_pwr_key_pm_ops
,
286 .of_match_table
= of_match_ptr(pm8941_pwr_key_id_table
),
289 module_platform_driver(pm8941_pwrkey_driver
);
291 MODULE_DESCRIPTION("PM8941 Power Key driver");
292 MODULE_LICENSE("GPL v2");