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