aboutsummaryrefslogtreecommitdiff
path: root/drivers/input/misc/hi6421_pwrkey.c
blob: 7b2098d1fe2ba025c09d24d7fcf6c7081335519b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * hi6421_pwrkey.c - Hisilicon Hi6421 PMIC ONKEY driver
 *
 * Copyright (C) 2013 Hisilicon Ltd.
 * Copyright (C) 2013 Linaro Ltd.
 * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
 *
 * This file is subject to the terms and conditions of the GNU General
 * Public License. See the file "COPYING" in the main directory of this
 * archive for more details.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/mfd/hi6421-pmic.h>

struct hi6421_onkey_info {
	struct input_dev	*idev;
	int			irq[4];
};

static irqreturn_t hi6421_onkey_handler(int irq, void *data)
{
	struct hi6421_onkey_info *info = (struct hi6421_onkey_info *)data;

	/* only handle power down & power up event at here */
	if (irq == info->irq[0]) {
		input_report_key(info->idev, KEY_POWER, 1);
		input_sync(info->idev);
	} else if (irq == info->irq[1]) {
		input_report_key(info->idev, KEY_POWER, 0);
		input_sync(info->idev);
	}
	return IRQ_HANDLED;
}

static int hi6421_onkey_probe(struct platform_device *pdev)
{
	struct hi6421_onkey_info *info;
	struct device *dev = &pdev->dev;
	int ret;

	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;
	info->irq[0] = platform_get_irq_byname(pdev, "down");
	if (info->irq[0] < 0)
		return -ENOENT;
	ret = request_irq(info->irq[0], hi6421_onkey_handler,
			  IRQF_DISABLED, "down", info);
	if (ret < 0)
		return ret;
	info->irq[1] = platform_get_irq_byname(pdev, "up");
	if (info->irq[1] < 0) {
		ret = -ENOENT;
		goto err;
	}
	ret = request_irq(info->irq[1], hi6421_onkey_handler,
			  IRQF_DISABLED, "up", info);
	if (ret < 0)
		goto err;
	info->irq[2] = platform_get_irq_byname(pdev, "hold 1s");
	if (info->irq[2] < 0) {
		ret = -ENOENT;
		goto err_irq2;
	}
	ret = request_irq(info->irq[2], hi6421_onkey_handler,
			  IRQF_DISABLED, "hold 1s", info);
	if (ret < 0)
		goto err_irq2;
	info->irq[3] = platform_get_irq_byname(pdev, "hold 10s");
	if (info->irq[3] < 0) {
		ret = -ENOENT;
		goto err_irq3;
	}
	ret = request_irq(info->irq[3], hi6421_onkey_handler,
			  IRQF_DISABLED, "hold 10s", info);
	if (ret < 0)
		goto err_irq3;

	info->idev = input_allocate_device();
	if (!info->idev) {
		dev_err(&pdev->dev, "Failed to allocate input device\n");
		goto err_alloc;
	}
	info->idev->name = "hi6421_on";
	info->idev->phys = "hi6421_on/input0";
	info->idev->dev.parent = &pdev->dev;
	info->idev->evbit[0] = BIT_MASK(EV_KEY);
	__set_bit(KEY_POWER, info->idev->keybit);

	ret = input_register_device(info->idev);
	if (ret) {
		dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
		goto err_reg;
	}

	platform_set_drvdata(pdev, info);
	return ret;
err_reg:
	input_free_device(info->idev);
err_alloc:
	free_irq(info->irq[3], info);
err_irq3:
	free_irq(info->irq[2], info);
err_irq2:
	free_irq(info->irq[1], info);
err:
	free_irq(info->irq[0], info);
	return ret;
}

static int hi6421_onkey_remove(struct platform_device *pdev)
{
	return 0;
}

static struct of_device_id hi6421_onkey_of_match[] = {
	{ .compatible = "hisilicon,hi6421-onkey", },
	{ },
};
MODULE_DEVICE_TABLE(of, hi6421_onkey_of_match);

static struct platform_driver hi6421_onkey_driver = {
	.probe		= hi6421_onkey_probe,
	.remove		= hi6421_onkey_remove,
	.driver		= {
		.owner		= THIS_MODULE,
		.name		= "hi6421-onkey",
		.of_match_table	= hi6421_onkey_of_match,
	},
};
module_platform_driver(hi6421_onkey_driver);

MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@linaro.org");
MODULE_DESCRIPTION("Hi6421 PMIC Power key driver");
MODULE_LICENSE("GPL v2");