Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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