xref: /linux/drivers/input/misc/pf1550-onkey.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
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 
20 struct onkey_drv_data {
21 	struct device *dev;
22 	const struct pf1550_ddata *pf1550;
23 	bool wakeup;
24 	struct input_dev *input;
25 };
26 
27 static 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(onkey->input, EV_KEY, KEY_POWER, state);
55 	input_sync(onkey->input);
56 
57 	return IRQ_HANDLED;
58 }
59 
60 static 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(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
68 	if (!onkey)
69 		return -ENOMEM;
70 
71 	onkey->dev = &pdev->dev;
72 
73 	onkey->pf1550 = dev_get_drvdata(pdev->dev.parent);
74 	if (!onkey->pf1550->regmap)
75 		return dev_err_probe(&pdev->dev, -ENODEV,
76 				     "failed to get regmap\n");
77 
78 	onkey->wakeup = device_property_read_bool(pdev->dev.parent,
79 						  "wakeup-source");
80 
81 	if (device_property_read_bool(pdev->dev.parent,
82 				      "nxp,disable-key-power")) {
83 		error = regmap_clear_bits(onkey->pf1550->regmap,
84 					  PF1550_PMIC_REG_PWRCTRL1,
85 					  PF1550_ONKEY_RST_EN);
86 		if (error)
87 			return dev_err_probe(&pdev->dev, error,
88 					     "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(&pdev->dev, -ENOMEM,
96 				     "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(input, EV_KEY, KEY_POWER);
104 
105 	onkey->input = input;
106 	platform_set_drvdata(pdev, 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(&pdev->dev, irq, NULL,
114 						  pf1550_onkey_irq_handler,
115 						  IRQF_NO_SUSPEND,
116 						  "pf1550-onkey", onkey);
117 		if (error)
118 			return dev_err_probe(&pdev->dev, error,
119 					     "failed: irq request (IRQ: %d)\n",
120 					     i);
121 	}
122 
123 	error = input_register_device(input);
124 	if (error)
125 		return dev_err_probe(&pdev->dev, error,
126 				     "failed to register input device\n");
127 
128 	device_init_wakeup(&pdev->dev, onkey->wakeup);
129 
130 	return 0;
131 }
132 
133 static 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(&pdev->dev))
140 		regmap_write(onkey->pf1550->regmap,
141 			     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 
154 static 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(&pdev->dev))
161 		regmap_write(onkey->pf1550->regmap,
162 			     PF1550_PMIC_REG_ONKEY_INT_MASK0,
163 			     ~((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 
176 static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend,
177 			 pf1550_onkey_resume);
178 
179 static const struct platform_device_id pf1550_onkey_id[] = {
180 	{ "pf1550-onkey", },
181 	{ /* sentinel */ }
182 };
183 MODULE_DEVICE_TABLE(platform, pf1550_onkey_id);
184 
185 static 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 };
193 module_platform_driver(pf1550_onkey_driver);
194 
195 MODULE_AUTHOR("Freescale Semiconductor");
196 MODULE_DESCRIPTION("PF1550 onkey Driver");
197 MODULE_LICENSE("GPL");
198