xref: /OK3568_Linux_fs/kernel/drivers/video/rockchip/vehicle/vehicle_gpio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * drivers/video/rockchip/video/vehicle_gpio.c
4  *
5  * Copyright (C) 2020 Rockchip Electronics Co.Ltd
6  * Authors:
7  *	Jianwei Fan <jianwei.fan@rock-chips.com>
8  *
9  */
10 
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/delay.h>
14 #include <linux/errno.h>
15 #include <linux/kernel.h>
16 #include <linux/time.h>
17 #include <linux/platform_device.h>
18 #include <linux/kthread.h>
19 #include <linux/clk.h>
20 #include <linux/clkdev.h>
21 #include <linux/completion.h>
22 #include <linux/wakelock.h>
23 #include <linux/of_gpio.h>
24 #include <linux/of_irq.h>
25 #include <linux/interrupt.h>
26 
27 #include "vehicle_gpio.h"
28 #include "vehicle_main.h"
29 
gpio_det_work_func(struct work_struct * work)30 static void gpio_det_work_func(struct work_struct *work)
31 {
32 	struct gpio_detect *gpiod = container_of(work, struct gpio_detect,
33 			work.work);
34 	int val = gpio_get_value(gpiod->gpio);
35 
36 	VEHICLE_DG("%s: gpiod->old val(%d), new val(%d)\n",
37 			__func__, gpiod->val, val);
38 
39 	if (gpiod->val != val) {
40 		gpiod->val = val;
41 		vehicle_gpio_stat_change_notify();
42 	}
43 }
44 
gpio_det_interrupt(int irq,void * dev_id)45 static irqreturn_t gpio_det_interrupt(int irq, void *dev_id)
46 {
47 	struct gpio_detect *gpiod = dev_id;
48 	int val = gpio_get_value(gpiod->gpio);
49 	unsigned int irqflags = IRQF_ONESHOT;
50 
51 	if (val)
52 		irqflags |= IRQ_TYPE_EDGE_FALLING;
53 	else
54 		irqflags |= IRQ_TYPE_EDGE_RISING;
55 	irq_set_irq_type(gpiod->irq, irqflags);
56 
57 	mod_delayed_work(system_wq, &gpiod->work,
58 			 msecs_to_jiffies(gpiod->debounce_ms));
59 
60 	return IRQ_HANDLED;
61 }
62 
vehicle_gpio_init_check(struct gpio_detect * gpiod)63 static int vehicle_gpio_init_check(struct gpio_detect *gpiod)
64 {
65 	gpiod->val = gpio_get_value(gpiod->gpio);
66 
67 	dev_info(gpiod->dev, "%s: gpiod->atv_val(%d), gpiod->val(%d)\n",
68 			__func__, gpiod->atv_val, gpiod->val);
69 
70 	if (gpiod->atv_val == gpiod->val) {
71 		vehicle_gpio_stat_change_notify();
72 		return 1;
73 	} else {
74 		return 0;
75 	}
76 }
77 
vehicle_gpio_reverse_check(struct gpio_detect * gpiod)78 bool vehicle_gpio_reverse_check(struct gpio_detect *gpiod)
79 {
80 	int val = gpiod->val ^ gpiod->atv_val;
81 
82 	if (gpiod->num == 0)
83 		return true;
84 	else
85 		return (val == 0) ? true : false;
86 }
87 
gpio_parse_dt(struct gpio_detect * gpiod,const char * ad_name)88 static int gpio_parse_dt(struct gpio_detect *gpiod, const char *ad_name)
89 {
90 	struct device *dev = gpiod->dev;
91 	struct device_node *gpiod_node;
92 	struct device_node *node;
93 	const char *name;
94 	int ret = 0;
95 
96 	gpiod_node = of_parse_phandle(dev->of_node, "rockchip,gpio-det", 0);
97 	if (!gpiod_node) {
98 		VEHICLE_DGERR("phase gpio-det from dts failed, maybe no use!\n");
99 		return -EINVAL;
100 	}
101 
102 	gpiod->num = of_get_child_count(gpiod_node);
103 	if (gpiod->num == 0) {
104 		VEHICLE_DGERR("gpio-det child count is 0, maybe no use!\n");
105 		return -EINVAL;
106 	}
107 
108 	for_each_child_of_node(gpiod_node, node) {
109 		enum of_gpio_flags flags;
110 
111 		name = of_get_property(node, "label", NULL);
112 		if (!strcmp(name, "car-reverse")) {
113 			gpiod->gpio = of_get_named_gpio_flags(node, "car-reverse-gpios", 0, &flags);
114 			if (!gpio_is_valid(gpiod->gpio)) {
115 				dev_err(dev, "failed to get car reverse gpio\n");
116 				ret = -ENOMEM;
117 			}
118 			gpiod->atv_val = !(flags & OF_GPIO_ACTIVE_LOW);
119 			of_property_read_u32(node, "linux,debounce-ms",
120 						  &gpiod->debounce_ms);
121 			break;
122 		}
123 	}
124 
125 	VEHICLE_DG("%s:gpio %d, act_val %d, mirror %d, debounce_ms %d\n",
126 		__func__, gpiod->gpio, gpiod->atv_val, gpiod->mirror, gpiod->debounce_ms);
127 	return ret;
128 }
129 
vehicle_gpio_init(struct gpio_detect * gpiod,const char * ad_name)130 int vehicle_gpio_init(struct gpio_detect *gpiod, const char *ad_name)
131 {
132 	int gpio;
133 	int ret;
134 	unsigned long irqflags = IRQF_ONESHOT;
135 
136 	if (gpio_parse_dt(gpiod, ad_name) < 0) {
137 		VEHICLE_INFO("%s, gpio parse dt failed, maybe unuse gpio-det\n", __func__);
138 	} else {
139 		gpio = gpiod->gpio;
140 
141 		ret = gpio_request(gpio, "vehicle");
142 		if (ret < 0)
143 			VEHICLE_DGERR("%s:failed to request gpio %d, maybe no use\n",
144 					__func__, ret);
145 
146 		dev_info(gpiod->dev, "%s: request irq gpio(%d)\n", __func__, gpio);
147 		gpio_direction_input(gpio);
148 
149 		gpiod->irq = gpio_to_irq(gpio);
150 		if (gpiod->irq < 0)
151 			VEHICLE_DGERR("failed to get irq, GPIO %d, maybe no use\n", gpio);
152 
153 		gpiod->val = gpio_get_value(gpio);
154 		if (gpiod->val)
155 			irqflags |= IRQ_TYPE_EDGE_FALLING;
156 		else
157 			irqflags |= IRQ_TYPE_EDGE_RISING;
158 		ret = devm_request_threaded_irq(gpiod->dev, gpiod->irq,
159 					NULL, gpio_det_interrupt,
160 					irqflags, "vehicle gpio", gpiod);
161 		if (ret < 0)
162 			VEHICLE_DGERR("request irq(%s) failed:%d\n",
163 				"vehicle", ret);
164 	}
165 
166 	//if not add in create_workqueue only execute once;
167 	INIT_DELAYED_WORK(&gpiod->work, gpio_det_work_func);
168 
169 	vehicle_gpio_init_check(gpiod);
170 
171 	return 0;
172 }
173 
vehicle_gpio_deinit(struct gpio_detect * gpiod)174 int vehicle_gpio_deinit(struct gpio_detect *gpiod)
175 {
176 	gpio_free(gpiod->gpio);
177 	return 0;
178 }
179