Skip to content

Commit 842ea69

Browse files
committed
input: misc: add driver for max16150
MAX16150/MAX16169 nanoPower Pushbutton On/Off Controller Signed-off-by: Marc Paolo Sosa <marcpaolo.sosa@analog.com>
1 parent 880c0df commit 842ea69

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

drivers/input/misc/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ config INPUT_E3X0_BUTTON
150150
To compile this driver as a module, choose M here: the
151151
module will be called e3x0_button.
152152

153+
config INPUT_MAX16150_PWRBUTTON
154+
tristate "MAX16150/MAX16169 Pushbutton driver"
155+
help
156+
Say Y here if you want to enable power key reporting via
157+
MAX16150/MAX16169 nanoPower Pushbutton On/Off Controller.
158+
159+
To compile this driver as a module, choose M here. The module will
160+
be called max16150.
161+
153162
config INPUT_PCSPKR
154163
tristate "PC Speaker support"
155164
depends on PCSPKR_PLATFORM

drivers/input/misc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ obj-$(CONFIG_INPUT_IQS7222) += iqs7222.o
4949
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
5050
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
5151
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
52+
obj-$(CONFIG_INPUT_MAX16150_PWRBUTTON) += max16150.o
5253
obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o
5354
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
5455
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o

drivers/input/misc/max16150.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Analog Devices MAX16150/MAX16169 Pushbutton Driver
4+
*
5+
* Copyright 2025 Analog Devices Inc.
6+
*/
7+
8+
#include <linux/errno.h>
9+
#include <linux/init.h>
10+
#include <linux/input.h>
11+
#include <linux/interrupt.h>
12+
#include <linux/kernel.h>
13+
#include <linux/module.h>
14+
#include <linux/platform_device.h>
15+
#include <linux/ktime.h>
16+
#include <linux/of.h>
17+
#include <linux/mod_devicetable.h>
18+
19+
#define SHORT_PRESS_MIN_MS 32
20+
#define SHORT_PRESS_MAX_MS 127
21+
#define LONG_PRESS_MIN_MS 128
22+
23+
struct max16150_data {
24+
struct input_dev *bttn;
25+
int key_event;
26+
ktime_t irq_rising_time;
27+
ktime_t irq_falling_time;
28+
};
29+
30+
static irqreturn_t max16150_rise_irq(int irq, void *_data)
31+
{
32+
struct max16150_data *data = _data;
33+
struct input_dev *bttn = data->bttn;
34+
35+
data->irq_rising_time = ktime_get();
36+
37+
input_report_key(bttn, data->key_event, 1);
38+
input_sync(bttn);
39+
40+
return IRQ_HANDLED;
41+
}
42+
43+
static irqreturn_t max16150_fall_irq(int irq, void *_data)
44+
{
45+
struct max16150_data *data = _data;
46+
struct input_dev *bttn = data->bttn;
47+
struct device *dev = bttn->dev.parent;
48+
ktime_t irq_duration;
49+
unsigned long duration_ms;
50+
51+
data->irq_falling_time = ktime_get();
52+
irq_duration = ktime_sub(data->irq_falling_time, data->irq_rising_time);
53+
duration_ms = ktime_to_ms(irq_duration);
54+
55+
dev_dbg_ratelimited(dev, "Interrupt duration: %lu ms\n", duration_ms);
56+
57+
if (duration_ms >= SHORT_PRESS_MIN_MS && duration_ms <= SHORT_PRESS_MAX_MS) {
58+
dev_info(dev, "Short press detected\n");
59+
input_event(bttn, EV_MSC, MSC_SCAN, 1);
60+
} else if (duration_ms >= LONG_PRESS_MIN_MS) {
61+
dev_info(dev, "Long press detected\n");
62+
input_event(bttn, EV_MSC, MSC_SCAN, 2);
63+
}
64+
65+
input_report_key(bttn, data->key_event, 0);
66+
input_sync(bttn);
67+
68+
return IRQ_HANDLED;
69+
}
70+
71+
static int max16150_probe(struct platform_device *pdev)
72+
{
73+
struct max16150_data *data;
74+
struct input_dev *bttn;
75+
int fall_irq, rise_irq, err;
76+
struct device_node *np = pdev->dev.of_node;
77+
78+
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
79+
if (!data)
80+
return -ENOMEM;
81+
82+
bttn = devm_input_allocate_device(&pdev->dev);
83+
if (!bttn) {
84+
dev_err(&pdev->dev, "Can't allocate input device\n");
85+
return -ENOMEM;
86+
}
87+
88+
data->bttn = bttn;
89+
if (of_property_read_u32(np, "key-event", &data->key_event))
90+
data->key_event = KEY_POWER;
91+
92+
bttn->name = "max16150";
93+
bttn->phys = "max16150/input0";
94+
bttn->id.bustype = BUS_HOST;
95+
input_set_capability(bttn, EV_KEY, data->key_event);
96+
input_set_capability(bttn, EV_MSC, MSC_SCAN);
97+
98+
fall_irq = platform_get_irq(pdev, 0);
99+
if (fall_irq < 0)
100+
return fall_irq;
101+
102+
rise_irq = platform_get_irq(pdev, 1);
103+
if (rise_irq < 0)
104+
return rise_irq;
105+
106+
err = devm_request_threaded_irq(&pdev->dev, rise_irq, NULL,
107+
max16150_rise_irq,
108+
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
109+
"max16150_rising", data);
110+
if (err < 0) {
111+
dev_err(&pdev->dev, "Can't register rise irq: %d\n", err);
112+
return err;
113+
}
114+
115+
err = devm_request_threaded_irq(&pdev->dev, fall_irq, NULL,
116+
max16150_fall_irq,
117+
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
118+
"max16150_falling", data);
119+
if (err < 0) {
120+
dev_err(&pdev->dev, "Can't register fall irq: %d\n", err);
121+
return err;
122+
}
123+
124+
err = input_register_device(bttn);
125+
if (err) {
126+
dev_err(&pdev->dev, "Can't register input device: %d\n", err);
127+
return err;
128+
}
129+
130+
platform_set_drvdata(pdev, data);
131+
device_init_wakeup(&pdev->dev, true);
132+
133+
return 0;
134+
}
135+
static const struct of_device_id max16150_of_match[] = {
136+
{ .compatible = "adi,max16150" },
137+
{ .compatible = "adi,max16169" },
138+
{ }
139+
};
140+
MODULE_DEVICE_TABLE(of, max16150_of_match);
141+
142+
static struct platform_driver max16150_driver = {
143+
.probe = max16150_probe,
144+
.driver = {
145+
.name = "max16150",
146+
.of_match_table = max16150_of_match,
147+
},
148+
};
149+
module_platform_driver(max16150_driver);
150+
151+
MODULE_AUTHOR("Marc Paolo Sosa <marcpaolo.sosa@analog.com>");
152+
MODULE_DESCRIPTION("MAX16150/MAX16169 Pushbutton Driver");
153+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)