File Index
Files and directories
Sign in
FILE

pf1550-onkey.c

File preview with syntax highlighting.

linux-6.19.14/drivers/input/misc/pf1550-onkey.c C
  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(onkey->input, EV_KEY, KEY_POWER, state);
 55	input_sync(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(&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
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(&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
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(&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
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");
~/ Read-only file preview.