1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * gpio detection driver
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2015 Rockchip Electronics Co., Ltd.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This software is licensed under the terms of the GNU General Public
7*4882a593Smuzhiyun * License version 2, as published by the Free Software Foundation, and
8*4882a593Smuzhiyun * may be copied, distributed, and modified under those terms.
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
11*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*4882a593Smuzhiyun * GNU General Public License for more details.
14*4882a593Smuzhiyun */
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/init.h>
18*4882a593Smuzhiyun #include <linux/device.h>
19*4882a593Smuzhiyun #include <linux/fb.h>
20*4882a593Smuzhiyun #include <linux/gpio_detection.h>
21*4882a593Smuzhiyun #include <linux/interrupt.h>
22*4882a593Smuzhiyun #include <linux/kernel.h>
23*4882a593Smuzhiyun #include <linux/of_gpio.h>
24*4882a593Smuzhiyun #include <linux/of_irq.h>
25*4882a593Smuzhiyun #include <linux/platform_device.h>
26*4882a593Smuzhiyun #include <linux/wakelock.h>
27*4882a593Smuzhiyun #include <linux/rk_keys.h>
28*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define WAKE_LOCK_TIMEOUT_MS (5000)
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun struct gpio_data {
33*4882a593Smuzhiyun struct gpio_detection *parent;
34*4882a593Smuzhiyun const char *name;
35*4882a593Smuzhiyun struct device dev;
36*4882a593Smuzhiyun int notify;
37*4882a593Smuzhiyun struct gpio_desc *gpio;
38*4882a593Smuzhiyun int val;
39*4882a593Smuzhiyun int irq;
40*4882a593Smuzhiyun struct delayed_work work;
41*4882a593Smuzhiyun unsigned int debounce_ms;
42*4882a593Smuzhiyun int wakeup;
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun struct gpio_detection {
46*4882a593Smuzhiyun struct class_attribute cls_attr;
47*4882a593Smuzhiyun struct device *dev;
48*4882a593Smuzhiyun int num;
49*4882a593Smuzhiyun struct gpio_data *data;
50*4882a593Smuzhiyun struct pinctrl *pinctrl;
51*4882a593Smuzhiyun struct pinctrl_state *pins_default;
52*4882a593Smuzhiyun struct notifier_block fb_notifier;
53*4882a593Smuzhiyun struct wake_lock wake_lock;
54*4882a593Smuzhiyun int mirror;
55*4882a593Smuzhiyun int type;
56*4882a593Smuzhiyun int info;
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun static struct class *gpio_detection_class;
60*4882a593Smuzhiyun static BLOCKING_NOTIFIER_HEAD(gpio_det_notifier_list);
61*4882a593Smuzhiyun static int system_suspend;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_GPIO_DET)
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun * gpio_det_notifier_call_chain - notify clients of gpio_det_events
67*4882a593Smuzhiyun *
68*4882a593Smuzhiyun */
gpio_det_notifier_call_chain(unsigned long val,void * v)69*4882a593Smuzhiyun int gpio_det_notifier_call_chain(unsigned long val, void *v)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun return blocking_notifier_call_chain(&gpio_det_notifier_list, val, v);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gpio_det_notifier_call_chain);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /*
76*4882a593Smuzhiyun * gpio_det_register_notifier - register a client notifier
77*4882a593Smuzhiyun * @nb: notifier block to callback on events
78*4882a593Smuzhiyun */
gpio_det_register_notifier(struct notifier_block * nb)79*4882a593Smuzhiyun int gpio_det_register_notifier(struct notifier_block *nb)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun int ret = blocking_notifier_chain_register(&gpio_det_notifier_list, nb);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun return ret;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun EXPORT_SYMBOL(gpio_det_register_notifier);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun /*
88*4882a593Smuzhiyun * gpio_det_unregister_client - unregister a client notifier
89*4882a593Smuzhiyun * @nb: notifier block to callback on events
90*4882a593Smuzhiyun */
gpio_det_unregister_notifier(struct notifier_block * nb)91*4882a593Smuzhiyun int gpio_det_unregister_notifier(struct notifier_block *nb)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun return blocking_notifier_chain_unregister(&gpio_det_notifier_list, nb);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun EXPORT_SYMBOL(gpio_det_unregister_notifier);
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun #endif
98*4882a593Smuzhiyun
gpio_det_report_event(struct gpio_data * gpiod)99*4882a593Smuzhiyun static void gpio_det_report_event(struct gpio_data *gpiod)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun struct gpio_event event;
102*4882a593Smuzhiyun struct gpio_detection *gpio_det = gpiod->parent;
103*4882a593Smuzhiyun char *status = NULL;
104*4882a593Smuzhiyun char *envp[2];
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun event.val = gpiod->val;
107*4882a593Smuzhiyun event.name = gpiod->name;
108*4882a593Smuzhiyun status = kasprintf(GFP_KERNEL, "GPIO_NAME=%s GPIO_STATE=%s",
109*4882a593Smuzhiyun gpiod->name, event.val ? "over" : "on");
110*4882a593Smuzhiyun envp[0] = status;
111*4882a593Smuzhiyun envp[1] = NULL;
112*4882a593Smuzhiyun wake_lock_timeout(&gpio_det->wake_lock,
113*4882a593Smuzhiyun msecs_to_jiffies(WAKE_LOCK_TIMEOUT_MS));
114*4882a593Smuzhiyun kobject_uevent_env(&gpiod->dev.kobj, KOBJ_CHANGE, envp);
115*4882a593Smuzhiyun if (gpiod->notify)
116*4882a593Smuzhiyun gpio_det_notifier_call_chain(GPIO_EVENT, &event);
117*4882a593Smuzhiyun kfree(status);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
gpio_det_work_func(struct work_struct * work)120*4882a593Smuzhiyun static void gpio_det_work_func(struct work_struct *work)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun struct gpio_data *gpiod = container_of(work, struct gpio_data,
123*4882a593Smuzhiyun work.work);
124*4882a593Smuzhiyun int val = gpiod_get_value(gpiod->gpio);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun if (gpiod->val != val) {
127*4882a593Smuzhiyun gpiod->val = val;
128*4882a593Smuzhiyun gpio_det_report_event(gpiod);
129*4882a593Smuzhiyun if (system_suspend && gpiod->wakeup) {
130*4882a593Smuzhiyun rk_send_power_key(1);
131*4882a593Smuzhiyun rk_send_power_key(0);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
gpio_det_interrupt(int irq,void * dev_id)136*4882a593Smuzhiyun static irqreturn_t gpio_det_interrupt(int irq, void *dev_id)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct gpio_data *gpiod = dev_id;
139*4882a593Smuzhiyun int val = gpiod_get_raw_value(gpiod->gpio);
140*4882a593Smuzhiyun unsigned int irqflags = IRQF_ONESHOT;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun if (val)
143*4882a593Smuzhiyun irqflags |= IRQ_TYPE_EDGE_FALLING;
144*4882a593Smuzhiyun else
145*4882a593Smuzhiyun irqflags |= IRQ_TYPE_EDGE_RISING;
146*4882a593Smuzhiyun irq_set_irq_type(gpiod->irq, irqflags);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun mod_delayed_work(system_wq, &gpiod->work,
149*4882a593Smuzhiyun msecs_to_jiffies(gpiod->debounce_ms));
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun return IRQ_HANDLED;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
gpio_det_init_status_check(struct gpio_detection * gpio_det)154*4882a593Smuzhiyun static int gpio_det_init_status_check(struct gpio_detection *gpio_det)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun struct gpio_data *gpiod;
157*4882a593Smuzhiyun int i;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun for (i = 0; i < gpio_det->num; i++) {
160*4882a593Smuzhiyun gpiod = &gpio_det->data[i];
161*4882a593Smuzhiyun gpiod->val = gpiod_get_value(gpiod->gpio);
162*4882a593Smuzhiyun if (gpiod->val)
163*4882a593Smuzhiyun gpio_det_report_event(gpiod);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun return 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
gpio_det_fb_notifier_callback(struct notifier_block * self,unsigned long event,void * data)169*4882a593Smuzhiyun static int gpio_det_fb_notifier_callback(struct notifier_block *self,
170*4882a593Smuzhiyun unsigned long event,
171*4882a593Smuzhiyun void *data)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun struct gpio_detection *gpio_det;
174*4882a593Smuzhiyun struct fb_event *evdata = data;
175*4882a593Smuzhiyun int fb_blank;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
178*4882a593Smuzhiyun return 0;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun gpio_det = container_of(self, struct gpio_detection, fb_notifier);
181*4882a593Smuzhiyun fb_blank = *(int *)evdata->data;
182*4882a593Smuzhiyun if (fb_blank == FB_BLANK_UNBLANK)
183*4882a593Smuzhiyun system_suspend = 0;
184*4882a593Smuzhiyun else
185*4882a593Smuzhiyun system_suspend = 1;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun return 0;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
gpio_det_fb_notifier_register(struct gpio_detection * gpio)190*4882a593Smuzhiyun static int gpio_det_fb_notifier_register(struct gpio_detection *gpio)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun gpio->fb_notifier.notifier_call = gpio_det_fb_notifier_callback;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun return fb_register_client(&gpio->fb_notifier);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
gpio_detection_info_show(struct class * class,struct class_attribute * attr,char * buf)197*4882a593Smuzhiyun static ssize_t gpio_detection_info_show(struct class *class,
198*4882a593Smuzhiyun struct class_attribute *attr,
199*4882a593Smuzhiyun char *buf)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun struct gpio_detection *gpio_det;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun gpio_det = container_of(attr, struct gpio_detection, cls_attr);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun return sprintf(buf, "%d\n", gpio_det->info);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
status_show(struct device * dev,struct device_attribute * attr,char * buf)208*4882a593Smuzhiyun static ssize_t status_show(struct device *dev, struct device_attribute *attr,
209*4882a593Smuzhiyun char *buf)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun struct gpio_data *gpiod = container_of(dev, struct gpio_data, dev);
212*4882a593Smuzhiyun unsigned int val = gpiod_get_value(gpiod->gpio);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun return sprintf(buf, "%d\n", val);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
status_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)217*4882a593Smuzhiyun static ssize_t status_store(struct device *dev, struct device_attribute *attr,
218*4882a593Smuzhiyun const char *buf, size_t count)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun struct gpio_data *gpiod;
221*4882a593Smuzhiyun int val;
222*4882a593Smuzhiyun int ret;
223*4882a593Smuzhiyun struct gpio_event event;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun gpiod = container_of(dev, struct gpio_data, dev);
226*4882a593Smuzhiyun ret = kstrtoint(buf, 0, &val);
227*4882a593Smuzhiyun if (ret < 0)
228*4882a593Smuzhiyun return ret;
229*4882a593Smuzhiyun if (val >= 0) {
230*4882a593Smuzhiyun event.val = val;
231*4882a593Smuzhiyun event.name = gpiod->name;
232*4882a593Smuzhiyun gpio_det_notifier_call_chain(GPIO_EVENT, &event);
233*4882a593Smuzhiyun } else {
234*4882a593Smuzhiyun gpiod->notify = 0;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun return count;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun static DEVICE_ATTR_RW(status);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun static struct attribute *gpio_detection_attrs[] = {
243*4882a593Smuzhiyun &dev_attr_status.attr,
244*4882a593Smuzhiyun NULL,
245*4882a593Smuzhiyun };
246*4882a593Smuzhiyun ATTRIBUTE_GROUPS(gpio_detection);
247*4882a593Smuzhiyun
gpio_deteciton_class_init(void)248*4882a593Smuzhiyun static int __init gpio_deteciton_class_init(void)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun gpio_detection_class = class_create(THIS_MODULE, "gpio-detection");
251*4882a593Smuzhiyun if (IS_ERR(gpio_detection_class)) {
252*4882a593Smuzhiyun pr_err("create gpio_detection class failed (%ld)\n",
253*4882a593Smuzhiyun PTR_ERR(gpio_detection_class));
254*4882a593Smuzhiyun return PTR_ERR(gpio_detection_class);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun return 0;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
gpio_detection_class_register(struct gpio_detection * gpio_det,struct gpio_data * gpiod)260*4882a593Smuzhiyun static int gpio_detection_class_register(struct gpio_detection *gpio_det,
261*4882a593Smuzhiyun struct gpio_data *gpiod)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun int ret;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun gpiod->dev.class = gpio_detection_class;
266*4882a593Smuzhiyun dev_set_name(&gpiod->dev, "%s", gpiod->name);
267*4882a593Smuzhiyun dev_set_drvdata(&gpiod->dev, gpio_det);
268*4882a593Smuzhiyun ret = device_register(&gpiod->dev);
269*4882a593Smuzhiyun ret = sysfs_create_groups(&gpiod->dev.kobj, gpio_detection_groups);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun return ret;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
gpio_det_parse_dt(struct gpio_detection * gpio_det,struct platform_device * pdev)274*4882a593Smuzhiyun static int gpio_det_parse_dt(struct gpio_detection *gpio_det,
275*4882a593Smuzhiyun struct platform_device *pdev)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun struct gpio_data *data;
278*4882a593Smuzhiyun struct device *dev = &pdev->dev;
279*4882a593Smuzhiyun struct device_node *node;
280*4882a593Smuzhiyun struct gpio_data *gpiod;
281*4882a593Smuzhiyun struct fwnode_handle *child;
282*4882a593Smuzhiyun int count = 0;
283*4882a593Smuzhiyun int i = 0;
284*4882a593Smuzhiyun int num = 0;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun num = of_get_child_count(gpio_det->dev->of_node);
287*4882a593Smuzhiyun count = device_get_child_node_count(dev);
288*4882a593Smuzhiyun if (!count || !num)
289*4882a593Smuzhiyun return -ENODEV;
290*4882a593Smuzhiyun data = devm_kzalloc(gpio_det->dev, num * sizeof(*data), GFP_KERNEL);
291*4882a593Smuzhiyun if (!data)
292*4882a593Smuzhiyun return -ENOMEM;
293*4882a593Smuzhiyun of_property_read_u32(gpio_det->dev->of_node, "rockchip,camcap-type",
294*4882a593Smuzhiyun &gpio_det->type);
295*4882a593Smuzhiyun of_property_read_u32(gpio_det->dev->of_node, "rockchip,camcap-mirror",
296*4882a593Smuzhiyun &gpio_det->mirror);
297*4882a593Smuzhiyun gpio_det->info = (gpio_det->mirror << 4) | gpio_det->type;
298*4882a593Smuzhiyun device_for_each_child_node(dev, child) {
299*4882a593Smuzhiyun node = to_of_node(child);
300*4882a593Smuzhiyun gpiod = &data[i++];
301*4882a593Smuzhiyun gpiod->parent = gpio_det;
302*4882a593Smuzhiyun gpiod->notify = 1;
303*4882a593Smuzhiyun gpiod->name = of_get_property(node, "label", NULL);
304*4882a593Smuzhiyun gpiod->wakeup = !!of_get_property(node, "gpio,wakeup", NULL);
305*4882a593Smuzhiyun of_property_read_u32(node, "linux,debounce-ms",
306*4882a593Smuzhiyun &gpiod->debounce_ms);
307*4882a593Smuzhiyun if (!strcmp(gpiod->name, "car-reverse"))
308*4882a593Smuzhiyun gpiod->gpio = devm_get_gpiod_from_child(dev,
309*4882a593Smuzhiyun "car-reverse", child);
310*4882a593Smuzhiyun else
311*4882a593Smuzhiyun gpiod->gpio = devm_get_gpiod_from_child(dev,
312*4882a593Smuzhiyun "car-acc", child);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun gpio_det->num = num;
315*4882a593Smuzhiyun gpio_det->data = data;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun return 0;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
gpio_det_probe(struct platform_device * pdev)320*4882a593Smuzhiyun static int gpio_det_probe(struct platform_device *pdev)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun struct gpio_detection *gpio_det;
323*4882a593Smuzhiyun struct gpio_data *gpiod;
324*4882a593Smuzhiyun unsigned long irqflags = IRQF_ONESHOT;
325*4882a593Smuzhiyun int i;
326*4882a593Smuzhiyun int ret;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun gpio_det = devm_kzalloc(&pdev->dev, sizeof(*gpio_det), GFP_KERNEL);
329*4882a593Smuzhiyun if (!gpio_det)
330*4882a593Smuzhiyun return -ENOMEM;
331*4882a593Smuzhiyun gpio_det->dev = &pdev->dev;
332*4882a593Smuzhiyun gpio_det->cls_attr.attr.name = "info";
333*4882a593Smuzhiyun gpio_det->cls_attr.attr.mode = S_IRUGO;
334*4882a593Smuzhiyun gpio_det->cls_attr.show = gpio_detection_info_show;
335*4882a593Smuzhiyun dev_set_name(gpio_det->dev, "gpio_detection");
336*4882a593Smuzhiyun if (!pdev->dev.of_node)
337*4882a593Smuzhiyun return -EINVAL;
338*4882a593Smuzhiyun gpio_det->pinctrl = devm_pinctrl_get(&pdev->dev);
339*4882a593Smuzhiyun if (IS_ERR(gpio_det->pinctrl)) {
340*4882a593Smuzhiyun dev_err(&pdev->dev, "pinctrl get failed\n");
341*4882a593Smuzhiyun return PTR_ERR(gpio_det->pinctrl);
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun gpio_det->pins_default = pinctrl_lookup_state(gpio_det->pinctrl,
344*4882a593Smuzhiyun PINCTRL_STATE_DEFAULT);
345*4882a593Smuzhiyun if (IS_ERR(gpio_det->pins_default))
346*4882a593Smuzhiyun dev_err(gpio_det->dev, "get default pinstate failed\n");
347*4882a593Smuzhiyun else
348*4882a593Smuzhiyun pinctrl_select_state(gpio_det->pinctrl, gpio_det->pins_default);
349*4882a593Smuzhiyun if (gpio_det_parse_dt(gpio_det, pdev))
350*4882a593Smuzhiyun return -ENODEV;
351*4882a593Smuzhiyun wake_lock_init(&gpio_det->wake_lock, WAKE_LOCK_SUSPEND,
352*4882a593Smuzhiyun "gpio_detection");
353*4882a593Smuzhiyun for (i = 0; i < gpio_det->num; i++) {
354*4882a593Smuzhiyun gpiod = &gpio_det->data[i];
355*4882a593Smuzhiyun gpiod_direction_input(gpiod->gpio);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun gpiod->irq = gpiod_to_irq(gpiod->gpio);
358*4882a593Smuzhiyun if (gpiod->irq < 0) {
359*4882a593Smuzhiyun dev_err(gpio_det->dev, "failed to get irq number for GPIO %s\n",
360*4882a593Smuzhiyun gpiod->name);
361*4882a593Smuzhiyun continue;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun ret = gpio_detection_class_register(gpio_det, gpiod);
365*4882a593Smuzhiyun if (ret < 0)
366*4882a593Smuzhiyun return ret;
367*4882a593Smuzhiyun INIT_DELAYED_WORK(&gpiod->work, gpio_det_work_func);
368*4882a593Smuzhiyun gpiod->val = gpiod_get_raw_value(gpiod->gpio);
369*4882a593Smuzhiyun if (gpiod->val)
370*4882a593Smuzhiyun irqflags |= IRQ_TYPE_EDGE_FALLING;
371*4882a593Smuzhiyun else
372*4882a593Smuzhiyun irqflags |= IRQ_TYPE_EDGE_RISING;
373*4882a593Smuzhiyun ret = devm_request_threaded_irq(gpio_det->dev, gpiod->irq,
374*4882a593Smuzhiyun NULL, gpio_det_interrupt,
375*4882a593Smuzhiyun irqflags | IRQF_ONESHOT,
376*4882a593Smuzhiyun gpiod->name, gpiod);
377*4882a593Smuzhiyun if (ret < 0)
378*4882a593Smuzhiyun dev_err(gpio_det->dev, "request irq(%s) failed:%d\n",
379*4882a593Smuzhiyun gpiod->name, ret);
380*4882a593Smuzhiyun else
381*4882a593Smuzhiyun if (gpiod->wakeup)
382*4882a593Smuzhiyun enable_irq_wake(gpiod->irq);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun if (gpio_det->info) {
386*4882a593Smuzhiyun ret = class_create_file(gpio_detection_class,
387*4882a593Smuzhiyun &gpio_det->cls_attr);
388*4882a593Smuzhiyun if (ret)
389*4882a593Smuzhiyun dev_warn(gpio_det->dev, "create class file failed:%d\n",
390*4882a593Smuzhiyun ret);
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun gpio_det_fb_notifier_register(gpio_det);
394*4882a593Smuzhiyun gpio_det_init_status_check(gpio_det);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun dev_info(gpio_det->dev, "gpio detection driver probe success\n");
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun return 0;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun #if defined(CONFIG_OF)
402*4882a593Smuzhiyun static const struct of_device_id gpio_det_of_match[] = {
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun .compatible = "gpio-detection"
405*4882a593Smuzhiyun },
406*4882a593Smuzhiyun {},
407*4882a593Smuzhiyun };
408*4882a593Smuzhiyun #endif
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun static struct platform_driver gpio_det_driver = {
411*4882a593Smuzhiyun .driver = {
412*4882a593Smuzhiyun .name = "gpio-detection",
413*4882a593Smuzhiyun .of_match_table = of_match_ptr(gpio_det_of_match),
414*4882a593Smuzhiyun },
415*4882a593Smuzhiyun .probe = gpio_det_probe,
416*4882a593Smuzhiyun };
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_REVERSE_IMAGE
gpio_det_init(void)419*4882a593Smuzhiyun int gpio_det_init(void)
420*4882a593Smuzhiyun #else
421*4882a593Smuzhiyun static int __init gpio_det_init(void)
422*4882a593Smuzhiyun #endif
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun if (!gpio_deteciton_class_init())
425*4882a593Smuzhiyun return platform_driver_register(&gpio_det_driver);
426*4882a593Smuzhiyun else
427*4882a593Smuzhiyun return -1;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun #ifndef CONFIG_VIDEO_REVERSE_IMAGE
431*4882a593Smuzhiyun fs_initcall_sync(gpio_det_init);
432*4882a593Smuzhiyun #endif
gpio_det_exit(void)433*4882a593Smuzhiyun static void __exit gpio_det_exit(void)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun platform_driver_unregister(&gpio_det_driver);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun module_exit(gpio_det_exit);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun MODULE_LICENSE("GPL");
441*4882a593Smuzhiyun MODULE_ALIAS("platform:gpio-detection");
442*4882a593Smuzhiyun MODULE_AUTHOR("ROCKCHIP");
443