1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Driver for the PF1550 ONKEY
4 * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
5 *
6 * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
7 * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
8 */
9
10#include <linux/err.h>
11#include <linux/input.h>
12#include <linux/interrupt.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/mfd/pf1550.h>
16#include <linux/platform_device.h>
17
18#define PF1550_ONKEY_IRQ_NR 6
19
20struct onkey_drv_data {
21 struct device *dev;
22 const struct pf1550_ddata *pf1550;
23 bool wakeup;
24 struct input_dev *input;
25};
26
27static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data)
28{
29 struct onkey_drv_data *onkey = data;
30 struct platform_device *pdev = to_platform_device(onkey->dev);
31 int i, state, irq_type = -1;
32
33 for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++)
34 if (irq == platform_get_irq(pdev, i))
35 irq_type = i;
36
37 switch (irq_type) {
38 case PF1550_ONKEY_IRQ_PUSHI:
39 state = 0;
40 break;
41 case PF1550_ONKEY_IRQ_1SI:
42 case PF1550_ONKEY_IRQ_2SI:
43 case PF1550_ONKEY_IRQ_3SI:
44 case PF1550_ONKEY_IRQ_4SI:
45 case PF1550_ONKEY_IRQ_8SI:
46 state = 1;
47 break;
48 default:
49 dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n",
50 irq_type);
51 return IRQ_HANDLED;
52 }
53
54 input_event(dev: onkey->input, EV_KEY, KEY_POWER, value: state);
55 input_sync(dev: onkey->input);
56
57 return IRQ_HANDLED;
58}
59
60static int pf1550_onkey_probe(struct platform_device *pdev)
61{
62 struct onkey_drv_data *onkey;
63 struct input_dev *input;
64 bool key_power = false;
65 int i, irq, error;
66
67 onkey = devm_kzalloc(dev: &pdev->dev, size: sizeof(*onkey), GFP_KERNEL);
68 if (!onkey)
69 return -ENOMEM;
70
71 onkey->dev = &pdev->dev;
72
73 onkey->pf1550 = dev_get_drvdata(dev: pdev->dev.parent);
74 if (!onkey->pf1550->regmap)
75 return dev_err_probe(dev: &pdev->dev, err: -ENODEV,
76 fmt: "failed to get regmap\n");
77
78 onkey->wakeup = device_property_read_bool(dev: pdev->dev.parent,
79 propname: "wakeup-source");
80
81 if (device_property_read_bool(dev: pdev->dev.parent,
82 propname: "nxp,disable-key-power")) {
83 error = regmap_clear_bits(map: onkey->pf1550->regmap,
84 reg: PF1550_PMIC_REG_PWRCTRL1,
85 PF1550_ONKEY_RST_EN);
86 if (error)
87 return dev_err_probe(dev: &pdev->dev, err: error,
88 fmt: "failed: disable turn system off");
89 } else {
90 key_power = true;
91 }
92
93 input = devm_input_allocate_device(&pdev->dev);
94 if (!input)
95 return dev_err_probe(dev: &pdev->dev, err: -ENOMEM,
96 fmt: "failed to allocate the input device\n");
97
98 input->name = pdev->name;
99 input->phys = "pf1550-onkey/input0";
100 input->id.bustype = BUS_HOST;
101
102 if (key_power)
103 input_set_capability(dev: input, EV_KEY, KEY_POWER);
104
105 onkey->input = input;
106 platform_set_drvdata(pdev, data: onkey);
107
108 for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
109 irq = platform_get_irq(pdev, i);
110 if (irq < 0)
111 return irq;
112
113 error = devm_request_threaded_irq(dev: &pdev->dev, irq, NULL,
114 thread_fn: pf1550_onkey_irq_handler,
115 IRQF_NO_SUSPEND,
116 devname: "pf1550-onkey", dev_id: onkey);
117 if (error)
118 return dev_err_probe(dev: &pdev->dev, err: error,
119 fmt: "failed: irq request (IRQ: %d)\n",
120 i);
121 }
122
123 error = input_register_device(input);
124 if (error)
125 return dev_err_probe(dev: &pdev->dev, err: error,
126 fmt: "failed to register input device\n");
127
128 device_init_wakeup(dev: &pdev->dev, enable: onkey->wakeup);
129
130 return 0;
131}
132
133static int pf1550_onkey_suspend(struct device *dev)
134{
135 struct platform_device *pdev = to_platform_device(dev);
136 struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
137 int i, irq;
138
139 if (!device_may_wakeup(dev: &pdev->dev))
140 regmap_write(map: onkey->pf1550->regmap,
141 reg: PF1550_PMIC_REG_ONKEY_INT_MASK0,
142 ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI |
143 ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI);
144 else
145 for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
146 irq = platform_get_irq(pdev, i);
147 if (irq > 0)
148 enable_irq_wake(irq);
149 }
150
151 return 0;
152}
153
154static int pf1550_onkey_resume(struct device *dev)
155{
156 struct platform_device *pdev = to_platform_device(dev);
157 struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
158 int i, irq;
159
160 if (!device_may_wakeup(dev: &pdev->dev))
161 regmap_write(map: onkey->pf1550->regmap,
162 reg: PF1550_PMIC_REG_ONKEY_INT_MASK0,
163 val: ~((u8)(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI |
164 ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI |
165 ONKEY_IRQ_8SI)));
166 else
167 for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
168 irq = platform_get_irq(pdev, i);
169 if (irq > 0)
170 disable_irq_wake(irq);
171 }
172
173 return 0;
174}
175
176static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend,
177 pf1550_onkey_resume);
178
179static const struct platform_device_id pf1550_onkey_id[] = {
180 { "pf1550-onkey", },
181 { /* sentinel */ }
182};
183MODULE_DEVICE_TABLE(platform, pf1550_onkey_id);
184
185static struct platform_driver pf1550_onkey_driver = {
186 .driver = {
187 .name = "pf1550-onkey",
188 .pm = pm_sleep_ptr(&pf1550_onkey_pm_ops),
189 },
190 .probe = pf1550_onkey_probe,
191 .id_table = pf1550_onkey_id,
192};
193module_platform_driver(pf1550_onkey_driver);
194
195MODULE_AUTHOR("Freescale Semiconductor");
196MODULE_DESCRIPTION("PF1550 onkey Driver");
197MODULE_LICENSE("GPL");
198

source code of linux/drivers/input/misc/pf1550-onkey.c