2 * axp20x power button driver.
4 * Copyright (C) 2013 Carlo Caione <carlo@caione.org>
6 * This file is subject to the terms and conditions of the GNU General
7 * Public License. See the file "COPYING" in the main directory of this
8 * archive for more details.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/acpi.h>
17 #include <linux/errno.h>
18 #include <linux/irq.h>
19 #include <linux/init.h>
20 #include <linux/input.h>
21 #include <linux/interrupt.h>
22 #include <linux/kernel.h>
23 #include <linux/mfd/axp20x.h>
24 #include <linux/module.h>
25 #include <linux/platform_device.h>
26 #include <linux/regmap.h>
27 #include <linux/slab.h>
29 #define AXP20X_PEK_STARTUP_MASK (0xc0)
30 #define AXP20X_PEK_SHUTDOWN_MASK (0x03)
33 const struct axp20x_time
*startup_time
;
34 unsigned int startup_mask
;
35 const struct axp20x_time
*shutdown_time
;
36 unsigned int shutdown_mask
;
40 struct axp20x_dev
*axp20x
;
41 struct input_dev
*input
;
42 struct axp20x_info
*info
;
52 static const struct axp20x_time startup_time
[] = {
53 { .time
= 128, .idx
= 0 },
54 { .time
= 1000, .idx
= 2 },
55 { .time
= 3000, .idx
= 1 },
56 { .time
= 2000, .idx
= 3 },
59 static const struct axp20x_time axp221_startup_time
[] = {
60 { .time
= 128, .idx
= 0 },
61 { .time
= 1000, .idx
= 1 },
62 { .time
= 2000, .idx
= 2 },
63 { .time
= 3000, .idx
= 3 },
66 static const struct axp20x_time shutdown_time
[] = {
67 { .time
= 4000, .idx
= 0 },
68 { .time
= 6000, .idx
= 1 },
69 { .time
= 8000, .idx
= 2 },
70 { .time
= 10000, .idx
= 3 },
73 static const struct axp20x_info axp20x_info
= {
74 .startup_time
= startup_time
,
75 .startup_mask
= AXP20X_PEK_STARTUP_MASK
,
76 .shutdown_time
= shutdown_time
,
77 .shutdown_mask
= AXP20X_PEK_SHUTDOWN_MASK
,
80 static const struct axp20x_info axp221_info
= {
81 .startup_time
= axp221_startup_time
,
82 .startup_mask
= AXP20X_PEK_STARTUP_MASK
,
83 .shutdown_time
= shutdown_time
,
84 .shutdown_mask
= AXP20X_PEK_SHUTDOWN_MASK
,
87 static ssize_t
axp20x_show_attr(struct device
*dev
,
88 const struct axp20x_time
*time
,
89 unsigned int mask
, char *buf
)
91 struct axp20x_pek
*axp20x_pek
= dev_get_drvdata(dev
);
95 ret
= regmap_read(axp20x_pek
->axp20x
->regmap
, AXP20X_PEK_KEY
, &val
);
100 val
>>= ffs(mask
) - 1;
102 for (i
= 0; i
< 4; i
++)
103 if (val
== time
[i
].idx
)
106 return sprintf(buf
, "%u\n", val
);
109 static ssize_t
axp20x_show_attr_startup(struct device
*dev
,
110 struct device_attribute
*attr
,
113 struct axp20x_pek
*axp20x_pek
= dev_get_drvdata(dev
);
115 return axp20x_show_attr(dev
, axp20x_pek
->info
->startup_time
,
116 axp20x_pek
->info
->startup_mask
, buf
);
119 static ssize_t
axp20x_show_attr_shutdown(struct device
*dev
,
120 struct device_attribute
*attr
,
123 struct axp20x_pek
*axp20x_pek
= dev_get_drvdata(dev
);
125 return axp20x_show_attr(dev
, axp20x_pek
->info
->shutdown_time
,
126 axp20x_pek
->info
->shutdown_mask
, buf
);
129 static ssize_t
axp20x_store_attr(struct device
*dev
,
130 const struct axp20x_time
*time
,
131 unsigned int mask
, const char *buf
,
134 struct axp20x_pek
*axp20x_pek
= dev_get_drvdata(dev
);
138 unsigned int val
, idx
= 0;
139 unsigned int best_err
= UINT_MAX
;
141 val_str
[sizeof(val_str
) - 1] = '\0';
142 strncpy(val_str
, buf
, sizeof(val_str
) - 1);
143 len
= strlen(val_str
);
145 if (len
&& val_str
[len
- 1] == '\n')
146 val_str
[len
- 1] = '\0';
148 ret
= kstrtouint(val_str
, 10, &val
);
152 for (i
= 3; i
>= 0; i
--) {
155 err
= abs(time
[i
].time
- val
);
156 if (err
< best_err
) {
165 idx
<<= ffs(mask
) - 1;
166 ret
= regmap_update_bits(axp20x_pek
->axp20x
->regmap
, AXP20X_PEK_KEY
,
174 static ssize_t
axp20x_store_attr_startup(struct device
*dev
,
175 struct device_attribute
*attr
,
176 const char *buf
, size_t count
)
178 struct axp20x_pek
*axp20x_pek
= dev_get_drvdata(dev
);
180 return axp20x_store_attr(dev
, axp20x_pek
->info
->startup_time
,
181 axp20x_pek
->info
->startup_mask
, buf
, count
);
184 static ssize_t
axp20x_store_attr_shutdown(struct device
*dev
,
185 struct device_attribute
*attr
,
186 const char *buf
, size_t count
)
188 struct axp20x_pek
*axp20x_pek
= dev_get_drvdata(dev
);
190 return axp20x_store_attr(dev
, axp20x_pek
->info
->shutdown_time
,
191 axp20x_pek
->info
->shutdown_mask
, buf
, count
);
194 DEVICE_ATTR(startup
, 0644, axp20x_show_attr_startup
, axp20x_store_attr_startup
);
195 DEVICE_ATTR(shutdown
, 0644, axp20x_show_attr_shutdown
,
196 axp20x_store_attr_shutdown
);
198 static struct attribute
*axp20x_attrs
[] = {
199 &dev_attr_startup
.attr
,
200 &dev_attr_shutdown
.attr
,
203 ATTRIBUTE_GROUPS(axp20x
);
205 static irqreturn_t
axp20x_pek_irq(int irq
, void *pwr
)
207 struct input_dev
*idev
= pwr
;
208 struct axp20x_pek
*axp20x_pek
= input_get_drvdata(idev
);
211 * The power-button is connected to ground so a falling edge (dbf)
212 * means it is pressed.
214 if (irq
== axp20x_pek
->irq_dbf
)
215 input_report_key(idev
, KEY_POWER
, true);
216 else if (irq
== axp20x_pek
->irq_dbr
)
217 input_report_key(idev
, KEY_POWER
, false);
224 static int axp20x_pek_probe_input_device(struct axp20x_pek
*axp20x_pek
,
225 struct platform_device
*pdev
)
227 struct axp20x_dev
*axp20x
= axp20x_pek
->axp20x
;
228 struct input_dev
*idev
;
231 axp20x_pek
->irq_dbr
= platform_get_irq_byname(pdev
, "PEK_DBR");
232 if (axp20x_pek
->irq_dbr
< 0)
233 return axp20x_pek
->irq_dbr
;
234 axp20x_pek
->irq_dbr
= regmap_irq_get_virq(axp20x
->regmap_irqc
,
235 axp20x_pek
->irq_dbr
);
237 axp20x_pek
->irq_dbf
= platform_get_irq_byname(pdev
, "PEK_DBF");
238 if (axp20x_pek
->irq_dbf
< 0)
239 return axp20x_pek
->irq_dbf
;
240 axp20x_pek
->irq_dbf
= regmap_irq_get_virq(axp20x
->regmap_irqc
,
241 axp20x_pek
->irq_dbf
);
243 axp20x_pek
->input
= devm_input_allocate_device(&pdev
->dev
);
244 if (!axp20x_pek
->input
)
247 idev
= axp20x_pek
->input
;
249 idev
->name
= "axp20x-pek";
250 idev
->phys
= "m1kbd/input2";
251 idev
->dev
.parent
= &pdev
->dev
;
253 input_set_capability(idev
, EV_KEY
, KEY_POWER
);
255 input_set_drvdata(idev
, axp20x_pek
);
257 error
= devm_request_any_context_irq(&pdev
->dev
, axp20x_pek
->irq_dbr
,
259 "axp20x-pek-dbr", idev
);
261 dev_err(&pdev
->dev
, "Failed to request dbr IRQ#%d: %d\n",
262 axp20x_pek
->irq_dbr
, error
);
266 error
= devm_request_any_context_irq(&pdev
->dev
, axp20x_pek
->irq_dbf
,
268 "axp20x-pek-dbf", idev
);
270 dev_err(&pdev
->dev
, "Failed to request dbf IRQ#%d: %d\n",
271 axp20x_pek
->irq_dbf
, error
);
275 error
= input_register_device(idev
);
277 dev_err(&pdev
->dev
, "Can't register input device: %d\n",
282 if (axp20x_pek
->axp20x
->variant
== AXP288_ID
)
283 enable_irq_wake(axp20x_pek
->irq_dbr
);
289 static bool axp20x_pek_should_register_input(struct axp20x_pek
*axp20x_pek
,
290 struct platform_device
*pdev
)
292 unsigned long long hrv
= 0;
295 if (IS_ENABLED(CONFIG_INPUT_SOC_BUTTON_ARRAY
) &&
296 axp20x_pek
->axp20x
->variant
== AXP288_ID
) {
297 status
= acpi_evaluate_integer(ACPI_HANDLE(pdev
->dev
.parent
),
299 if (ACPI_FAILURE(status
))
300 dev_err(&pdev
->dev
, "Failed to get PMIC hardware revision\n");
303 * On Cherry Trail platforms (hrv == 3), do not register the
304 * input device if there is an "INTCFD9" or "ACPI0011" gpio
305 * button ACPI device, as that handles the power button too,
306 * and otherwise we end up reporting all presses twice.
308 if (hrv
== 3 && (acpi_dev_present("INTCFD9", NULL
, -1) ||
309 acpi_dev_present("ACPI0011", NULL
, -1)))
317 static bool axp20x_pek_should_register_input(struct axp20x_pek
*axp20x_pek
,
318 struct platform_device
*pdev
)
324 static int axp20x_pek_probe(struct platform_device
*pdev
)
326 struct axp20x_pek
*axp20x_pek
;
327 const struct platform_device_id
*match
= platform_get_device_id(pdev
);
331 dev_err(&pdev
->dev
, "Failed to get platform_device_id\n");
335 axp20x_pek
= devm_kzalloc(&pdev
->dev
, sizeof(struct axp20x_pek
),
340 axp20x_pek
->axp20x
= dev_get_drvdata(pdev
->dev
.parent
);
342 if (axp20x_pek_should_register_input(axp20x_pek
, pdev
)) {
343 error
= axp20x_pek_probe_input_device(axp20x_pek
, pdev
);
348 axp20x_pek
->info
= (struct axp20x_info
*)match
->driver_data
;
350 platform_set_drvdata(pdev
, axp20x_pek
);
355 static int __maybe_unused
axp20x_pek_resume_noirq(struct device
*dev
)
357 struct axp20x_pek
*axp20x_pek
= dev_get_drvdata(dev
);
359 if (axp20x_pek
->axp20x
->variant
!= AXP288_ID
)
363 * Clear interrupts from button presses during suspend, to avoid
364 * a wakeup power-button press getting reported to userspace.
366 regmap_write(axp20x_pek
->axp20x
->regmap
,
367 AXP20X_IRQ1_STATE
+ AXP288_IRQ_POKN
/ 8,
368 BIT(AXP288_IRQ_POKN
% 8));
373 static const struct dev_pm_ops axp20x_pek_pm_ops
= {
374 #ifdef CONFIG_PM_SLEEP
375 .resume_noirq
= axp20x_pek_resume_noirq
,
379 static const struct platform_device_id axp_pek_id_match
[] = {
381 .name
= "axp20x-pek",
382 .driver_data
= (kernel_ulong_t
)&axp20x_info
,
385 .name
= "axp221-pek",
386 .driver_data
= (kernel_ulong_t
)&axp221_info
,
390 MODULE_DEVICE_TABLE(platform
, axp_pek_id_match
);
392 static struct platform_driver axp20x_pek_driver
= {
393 .probe
= axp20x_pek_probe
,
394 .id_table
= axp_pek_id_match
,
396 .name
= "axp20x-pek",
397 .pm
= &axp20x_pek_pm_ops
,
398 .dev_groups
= axp20x_groups
,
401 module_platform_driver(axp20x_pek_driver
);
403 MODULE_DESCRIPTION("axp20x Power Button");
404 MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
405 MODULE_LICENSE("GPL");