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