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