xref: /OK3568_Linux_fs/kernel/drivers/input/misc/sirfsoc-onkey.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Power key driver for SiRF PrimaII
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2013 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
6*4882a593Smuzhiyun  * company.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/platform_device.h>
13*4882a593Smuzhiyun #include <linux/input.h>
14*4882a593Smuzhiyun #include <linux/rtc/sirfsoc_rtciobrg.h>
15*4882a593Smuzhiyun #include <linux/of.h>
16*4882a593Smuzhiyun #include <linux/workqueue.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun struct sirfsoc_pwrc_drvdata {
19*4882a593Smuzhiyun 	u32			pwrc_base;
20*4882a593Smuzhiyun 	struct input_dev	*input;
21*4882a593Smuzhiyun 	struct delayed_work	work;
22*4882a593Smuzhiyun };
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define PWRC_ON_KEY_BIT			(1 << 0)
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define PWRC_INT_STATUS			0xc
27*4882a593Smuzhiyun #define PWRC_INT_MASK			0x10
28*4882a593Smuzhiyun #define PWRC_PIN_STATUS			0x14
29*4882a593Smuzhiyun #define PWRC_KEY_DETECT_UP_TIME		20	/* ms*/
30*4882a593Smuzhiyun 
sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata * pwrcdrv)31*4882a593Smuzhiyun static int sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata *pwrcdrv)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	u32 state = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
34*4882a593Smuzhiyun 							PWRC_PIN_STATUS);
35*4882a593Smuzhiyun 	return !(state & PWRC_ON_KEY_BIT); /* ON_KEY is active low */
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun 
sirfsoc_pwrc_report_event(struct work_struct * work)38*4882a593Smuzhiyun static void sirfsoc_pwrc_report_event(struct work_struct *work)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	struct sirfsoc_pwrc_drvdata *pwrcdrv =
41*4882a593Smuzhiyun 		container_of(work, struct sirfsoc_pwrc_drvdata, work.work);
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	if (sirfsoc_pwrc_is_on_key_down(pwrcdrv)) {
44*4882a593Smuzhiyun 		schedule_delayed_work(&pwrcdrv->work,
45*4882a593Smuzhiyun 			msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
46*4882a593Smuzhiyun 	} else {
47*4882a593Smuzhiyun 		input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 0);
48*4882a593Smuzhiyun 		input_sync(pwrcdrv->input);
49*4882a593Smuzhiyun 	}
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun 
sirfsoc_pwrc_isr(int irq,void * dev_id)52*4882a593Smuzhiyun static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
55*4882a593Smuzhiyun 	u32 int_status;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
58*4882a593Smuzhiyun 							PWRC_INT_STATUS);
59*4882a593Smuzhiyun 	sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
60*4882a593Smuzhiyun 				 pwrcdrv->pwrc_base + PWRC_INT_STATUS);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 1);
63*4882a593Smuzhiyun 	input_sync(pwrcdrv->input);
64*4882a593Smuzhiyun 	schedule_delayed_work(&pwrcdrv->work,
65*4882a593Smuzhiyun 			      msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	return IRQ_HANDLED;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
sirfsoc_pwrc_toggle_interrupts(struct sirfsoc_pwrc_drvdata * pwrcdrv,bool enable)70*4882a593Smuzhiyun static void sirfsoc_pwrc_toggle_interrupts(struct sirfsoc_pwrc_drvdata *pwrcdrv,
71*4882a593Smuzhiyun 					   bool enable)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	u32 int_mask;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	int_mask = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK);
76*4882a593Smuzhiyun 	if (enable)
77*4882a593Smuzhiyun 		int_mask |= PWRC_ON_KEY_BIT;
78*4882a593Smuzhiyun 	else
79*4882a593Smuzhiyun 		int_mask &= ~PWRC_ON_KEY_BIT;
80*4882a593Smuzhiyun 	sirfsoc_rtc_iobrg_writel(int_mask, pwrcdrv->pwrc_base + PWRC_INT_MASK);
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
sirfsoc_pwrc_open(struct input_dev * input)83*4882a593Smuzhiyun static int sirfsoc_pwrc_open(struct input_dev *input)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	return 0;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
sirfsoc_pwrc_close(struct input_dev * input)92*4882a593Smuzhiyun static void sirfsoc_pwrc_close(struct input_dev *input)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
97*4882a593Smuzhiyun 	cancel_delayed_work_sync(&pwrcdrv->work);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun static const struct of_device_id sirfsoc_pwrc_of_match[] = {
101*4882a593Smuzhiyun 	{ .compatible = "sirf,prima2-pwrc" },
102*4882a593Smuzhiyun 	{},
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
105*4882a593Smuzhiyun 
sirfsoc_pwrc_probe(struct platform_device * pdev)106*4882a593Smuzhiyun static int sirfsoc_pwrc_probe(struct platform_device *pdev)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	struct device_node *np = pdev->dev.of_node;
109*4882a593Smuzhiyun 	struct sirfsoc_pwrc_drvdata *pwrcdrv;
110*4882a593Smuzhiyun 	int irq;
111*4882a593Smuzhiyun 	int error;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata),
114*4882a593Smuzhiyun 			       GFP_KERNEL);
115*4882a593Smuzhiyun 	if (!pwrcdrv) {
116*4882a593Smuzhiyun 		dev_info(&pdev->dev, "Not enough memory for the device data\n");
117*4882a593Smuzhiyun 		return -ENOMEM;
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	/*
121*4882a593Smuzhiyun 	 * We can't use of_iomap because pwrc is not mapped in memory,
122*4882a593Smuzhiyun 	 * the so-called base address is only offset in rtciobrg
123*4882a593Smuzhiyun 	 */
124*4882a593Smuzhiyun 	error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
125*4882a593Smuzhiyun 	if (error) {
126*4882a593Smuzhiyun 		dev_err(&pdev->dev,
127*4882a593Smuzhiyun 			"unable to find base address of pwrc node in dtb\n");
128*4882a593Smuzhiyun 		return error;
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	pwrcdrv->input = devm_input_allocate_device(&pdev->dev);
132*4882a593Smuzhiyun 	if (!pwrcdrv->input)
133*4882a593Smuzhiyun 		return -ENOMEM;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	pwrcdrv->input->name = "sirfsoc pwrckey";
136*4882a593Smuzhiyun 	pwrcdrv->input->phys = "pwrc/input0";
137*4882a593Smuzhiyun 	pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY);
138*4882a593Smuzhiyun 	input_set_capability(pwrcdrv->input, EV_KEY, KEY_POWER);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	pwrcdrv->input->open = sirfsoc_pwrc_open;
143*4882a593Smuzhiyun 	pwrcdrv->input->close = sirfsoc_pwrc_close;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	input_set_drvdata(pwrcdrv->input, pwrcdrv);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/* Make sure the device is quiesced */
148*4882a593Smuzhiyun 	sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
151*4882a593Smuzhiyun 	error = devm_request_irq(&pdev->dev, irq,
152*4882a593Smuzhiyun 				 sirfsoc_pwrc_isr, 0,
153*4882a593Smuzhiyun 				 "sirfsoc_pwrc_int", pwrcdrv);
154*4882a593Smuzhiyun 	if (error) {
155*4882a593Smuzhiyun 		dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
156*4882a593Smuzhiyun 			irq, error);
157*4882a593Smuzhiyun 		return error;
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	error = input_register_device(pwrcdrv->input);
161*4882a593Smuzhiyun 	if (error) {
162*4882a593Smuzhiyun 		dev_err(&pdev->dev,
163*4882a593Smuzhiyun 			"unable to register input device, error: %d\n",
164*4882a593Smuzhiyun 			error);
165*4882a593Smuzhiyun 		return error;
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	dev_set_drvdata(&pdev->dev, pwrcdrv);
169*4882a593Smuzhiyun 	device_init_wakeup(&pdev->dev, 1);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
sirfsoc_pwrc_resume(struct device * dev)174*4882a593Smuzhiyun static int __maybe_unused sirfsoc_pwrc_resume(struct device *dev)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_get_drvdata(dev);
177*4882a593Smuzhiyun 	struct input_dev *input = pwrcdrv->input;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	/*
180*4882a593Smuzhiyun 	 * Do not mask pwrc interrupt as we want pwrc work as a wakeup source
181*4882a593Smuzhiyun 	 * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
182*4882a593Smuzhiyun 	 */
183*4882a593Smuzhiyun 	mutex_lock(&input->mutex);
184*4882a593Smuzhiyun 	if (input->users)
185*4882a593Smuzhiyun 		sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
186*4882a593Smuzhiyun 	mutex_unlock(&input->mutex);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	return 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, sirfsoc_pwrc_resume);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun static struct platform_driver sirfsoc_pwrc_driver = {
194*4882a593Smuzhiyun 	.probe		= sirfsoc_pwrc_probe,
195*4882a593Smuzhiyun 	.driver		= {
196*4882a593Smuzhiyun 		.name	= "sirfsoc-pwrc",
197*4882a593Smuzhiyun 		.pm	= &sirfsoc_pwrc_pm_ops,
198*4882a593Smuzhiyun 		.of_match_table = sirfsoc_pwrc_of_match,
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun };
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun module_platform_driver(sirfsoc_pwrc_driver);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
205*4882a593Smuzhiyun MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
206*4882a593Smuzhiyun MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");
207*4882a593Smuzhiyun MODULE_ALIAS("platform:sirfsoc-pwrc");
208