1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2020 Rockchip Electronics Co. Ltd.
4 *
5 * Author: Bin Yang <yangbin@rock-chips.com>
6 */
7
8
9 #include <linux/platform_device.h>
10 #include <linux/interrupt.h>
11 #include <linux/i2c.h>
12 #include <linux/slab.h>
13 #include <linux/irq.h>
14 #include <linux/miscdevice.h>
15 #include <linux/gpio.h>
16 #include <linux/uaccess.h>
17 #include <linux/atomic.h>
18 #include <linux/delay.h>
19 #include <linux/input.h>
20 #include <linux/workqueue.h>
21 #include <linux/freezer.h>
22 #include <linux/of_gpio.h>
23 #include <linux/sensor-dev.h>
24 #include <linux/fb.h>
25 #include <linux/notifier.h>
26 #include <linux/rk_keys.h>
27 #include <linux/input.h>
28
29 struct mh248_para {
30 struct device *dev;
31 struct notifier_block fb_notif;
32 struct mutex ops_lock;
33 struct input_dev *hall_input;
34 int is_suspend;
35 int gpio_pin;
36 int irq;
37 int active_value;
38 };
39
hall_fb_notifier_callback(struct notifier_block * self,unsigned long action,void * data)40 static int hall_fb_notifier_callback(struct notifier_block *self,
41 unsigned long action, void *data)
42 {
43 struct mh248_para *mh248;
44 struct fb_event *event = data;
45
46 mh248 = container_of(self, struct mh248_para, fb_notif);
47
48 if (action != FB_EVENT_BLANK)
49 return NOTIFY_DONE;
50
51 mutex_lock(&mh248->ops_lock);
52 switch (*((int *)event->data)) {
53 case FB_BLANK_UNBLANK:
54 mh248->is_suspend = 0;
55 break;
56 default:
57 mh248->is_suspend = 1;
58 break;
59 }
60 mutex_unlock(&mh248->ops_lock);
61
62 return NOTIFY_OK;
63 }
64
hall_mh248_interrupt(int irq,void * dev_id)65 static irqreturn_t hall_mh248_interrupt(int irq, void *dev_id)
66 {
67 struct mh248_para *mh248 = (struct mh248_para *)dev_id;
68 int gpio_value = 0;
69
70 gpio_value = gpio_get_value(mh248->gpio_pin);
71 if ((gpio_value != mh248->active_value) &&
72 (mh248->is_suspend == 0)) {
73 input_report_key(mh248->hall_input, KEY_POWER, 1);
74 input_sync(mh248->hall_input);
75 input_report_key(mh248->hall_input, KEY_POWER, 0);
76 input_sync(mh248->hall_input);
77 } else if ((gpio_value == mh248->active_value) &&
78 (mh248->is_suspend == 1)) {
79 input_report_key(mh248->hall_input, KEY_WAKEUP, 1);
80 input_sync(mh248->hall_input);
81 input_report_key(mh248->hall_input, KEY_WAKEUP, 0);
82 input_sync(mh248->hall_input);
83 }
84
85 return IRQ_HANDLED;
86 }
87
hall_mh248_probe(struct platform_device * pdev)88 static int hall_mh248_probe(struct platform_device *pdev)
89 {
90 struct device_node *np = pdev->dev.of_node;
91 struct mh248_para *mh248;
92 enum of_gpio_flags irq_flags;
93 int hallactive = 0;
94 int ret = 0;
95
96 mh248 = devm_kzalloc(&pdev->dev, sizeof(*mh248), GFP_KERNEL);
97 if (!mh248)
98 return -ENOMEM;
99
100 mh248->dev = &pdev->dev;
101
102 mh248->gpio_pin = of_get_named_gpio_flags(np, "irq-gpio",
103 0, &irq_flags);
104 if (!gpio_is_valid(mh248->gpio_pin)) {
105 dev_err(mh248->dev, "Can not read property irq-gpio\n");
106 return mh248->gpio_pin;
107 }
108 mh248->irq = gpio_to_irq(mh248->gpio_pin);
109
110 of_property_read_u32(np, "hall-active", &hallactive);
111 mh248->active_value = hallactive;
112 mh248->is_suspend = 0;
113 mutex_init(&mh248->ops_lock);
114
115 ret = devm_gpio_request_one(mh248->dev, mh248->gpio_pin,
116 GPIOF_DIR_IN, "hall_mh248");
117 if (ret < 0) {
118 dev_err(mh248->dev, "fail to request gpio:%d\n", mh248->gpio_pin);
119 return ret;
120 }
121
122 ret = devm_request_threaded_irq(mh248->dev, mh248->irq,
123 NULL, hall_mh248_interrupt,
124 irq_flags | IRQF_NO_SUSPEND | IRQF_ONESHOT,
125 "hall_mh248", mh248);
126 if (ret < 0) {
127 dev_err(mh248->dev, "request irq(%d) failed, ret=%d\n",
128 mh248->irq, ret);
129 return ret;
130 }
131
132 mh248->hall_input = devm_input_allocate_device(&pdev->dev);
133 if (!mh248->hall_input) {
134 dev_err(&pdev->dev, "Can't allocate hall input dev\n");
135 return -ENOMEM;
136 }
137 mh248->hall_input->name = "hall wake key";
138 input_set_capability(mh248->hall_input, EV_KEY, KEY_POWER);
139 input_set_capability(mh248->hall_input, EV_KEY, KEY_WAKEUP);
140
141 ret = input_register_device(mh248->hall_input);
142 if (ret) {
143 dev_err(&pdev->dev, "Unable to register input device, error: %d\n", ret);
144 return ret;
145 }
146
147 enable_irq_wake(mh248->irq);
148 mh248->fb_notif.notifier_call = hall_fb_notifier_callback;
149 fb_register_client(&mh248->fb_notif);
150 dev_info(mh248->dev, "hall_mh248_probe success.\n");
151
152 return 0;
153 }
154
155 static const struct of_device_id hall_mh248_match[] = {
156 { .compatible = "hall-mh248" },
157 { /* Sentinel */ }
158 };
159
160 static struct platform_driver hall_mh248_driver = {
161 .probe = hall_mh248_probe,
162 .driver = {
163 .name = "mh248",
164 .owner = THIS_MODULE,
165 .of_match_table = hall_mh248_match,
166 },
167 };
168
169 module_platform_driver(hall_mh248_driver);
170
171 MODULE_ALIAS("platform:mh248");
172 MODULE_AUTHOR("Bin Yang <yangbin@rock-chips.com>");
173 MODULE_LICENSE("GPL v2");
174 MODULE_DESCRIPTION("Hall Sensor MH248 driver");
175