xref: /rk3399_rockchip-uboot/drivers/input/key-uclass.c (revision adba3792a71bd52a6f8276fae1acc1c323997d72)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <adc.h>
9 #include <dm.h>
10 #include <key.h>
11 
12 static LIST_HEAD(key_list);
13 
14 const char *evt_name[] = {
15 	"Not down",
16 	"Down",
17 	"Long down",
18 	"Not exist",
19 };
20 
21 static inline uint64_t arch_counter_get_cntpct(void)
22 {
23 	uint64_t cval = 0;
24 
25 	isb();
26 #ifdef CONFIG_ARM64
27 	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
28 #else
29 	asm volatile ("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
30 #endif
31 	return cval;
32 }
33 
34 uint64_t key_timer(uint64_t base)
35 {
36 	uint64_t cntpct;
37 
38 	cntpct = arch_counter_get_cntpct() / 24000UL;
39 	return (cntpct > base) ? (cntpct - base) : 0;
40 }
41 
42 /*
43  * What's simple and complex event mean?
44  *
45  * simple event:   key press down or none;
46  * complext event: key press down, long down or none;
47  */
48 static int key_read_adc_simple_event(struct input_key *key, unsigned int adcval)
49 {
50 	int max, min, margin = 30;
51 	int keyval;
52 
53 	/* Get min, max */
54 	max = key->adcval + margin;
55 	if (key->adcval > margin)
56 		min = key->adcval - margin;
57 	else
58 		min = 0;
59 
60 	debug("%s: '%s' configure adc=%d: range[%d~%d]; hw adcval=%d\n",
61 	      __func__, key->name, key->adcval, min, max, adcval);
62 
63 	/* Check */
64 	if ((adcval <= max) && (adcval >= min)) {
65 		keyval = KEY_PRESS_DOWN;
66 		debug("%s key pressed..\n", key->name);
67 	} else {
68 		keyval = KEY_PRESS_NONE;
69 	}
70 
71 	return keyval;
72 }
73 
74 static int key_read_gpio_simple_event(struct input_key *key)
75 {
76 	if (!dm_gpio_is_valid(&key->gpio)) {
77 		printf("%s: invalid gpio\n", key->name);
78 		return KEY_PRESS_NONE;
79 	}
80 
81 	return dm_gpio_get_value(&key->gpio) ? KEY_PRESS_DOWN : KEY_PRESS_NONE;
82 }
83 
84 static int key_read_gpio_complex_event(struct input_key *key)
85 {
86 	int keyval;
87 
88 	debug("%s: %s: up=%llu, down=%llu, delta=%llu\n",
89 	      __func__, key->name, key->up_t, key->down_t,
90 	      key->up_t - key->down_t);
91 
92 	/* Possible this is machine power-on long pressed, so ignore this */
93 	if (key->down_t == 0 && key->up_t != 0) {
94 		keyval = KEY_PRESS_NONE;
95 		goto out;
96 	}
97 
98 	if ((key->up_t > key->down_t) &&
99 	    (key->up_t - key->down_t) >= KEY_LONG_DOWN_MS) {
100 		key->up_t = 0;
101 		key->down_t = 0;
102 		keyval = KEY_PRESS_LONG_DOWN;
103 		debug("%s key long pressed..\n", key->name);
104 	} else if (key->down_t &&
105 		   key_timer(key->down_t) >= KEY_LONG_DOWN_MS) {
106 		key->up_t = 0;
107 		key->down_t = 0;
108 		keyval = KEY_PRESS_LONG_DOWN;
109 		debug("%s key long pressed(hold)..\n", key->name);
110 	} else if ((key->up_t > key->down_t) &&
111 		   (key->up_t - key->down_t) < KEY_LONG_DOWN_MS) {
112 		key->up_t = 0;
113 		key->down_t = 0;
114 		keyval = KEY_PRESS_DOWN;
115 		debug("%s key short pressed..\n", key->name);
116 	/* Possible in charge animation, we enable irq after fuel gauge updated */
117 	} else if (key->up_t && key->down_t && (key->up_t == key->down_t)){
118 		key->up_t = 0;
119 		key->down_t = 0;
120 		keyval = KEY_PRESS_DOWN;
121 		debug("%s key short pressed..\n", key->name);
122 	} else {
123 		keyval = KEY_PRESS_NONE;
124 	}
125 
126 out:
127 	return keyval;
128 }
129 
130 static int key_read_gpio_interrupt_event(struct input_key *key)
131 {
132 	debug("%s: %s\n", __func__, key->name);
133 
134 	return key_read_gpio_complex_event(key);
135 }
136 
137 int key_is_pressed(int keyval)
138 {
139 	return (keyval == KEY_PRESS_DOWN || keyval == KEY_PRESS_LONG_DOWN);
140 }
141 
142 void key_add(struct input_key *key)
143 {
144 	if (!key)
145 		return;
146 
147 	list_add_tail(&key->link, &key_list);
148 }
149 
150 int key_read(int code)
151 {
152 	struct udevice *dev;
153 	struct input_key *key;
154 	static int initialized;
155 	unsigned int adcval;
156 	int keyval = KEY_NOT_EXIST;
157 	int ret;
158 
159 	/* Initialize all key drivers */
160 	if (!initialized) {
161 		for (uclass_first_device(UCLASS_KEY, &dev);
162 		     dev;
163 		     uclass_next_device(&dev)) {
164 			debug("%s: have found key driver '%s'\n\n",
165 			      __func__, dev->name);
166 		}
167 	}
168 
169 	/* Search on the key list */
170 	list_for_each_entry(key, &key_list, link) {
171 		if (key->code != code)
172 			continue;
173 
174 		/* Is a adc key? */
175 		if (key->type & ADC_KEY) {
176 			ret = adc_channel_single_shot("saradc",
177 						      key->channel, &adcval);
178 			if (ret)
179 				printf("%s: failed to read saradc, ret=%d\n",
180 				       key->name, ret);
181 			else
182 				keyval = key_read_adc_simple_event(key, adcval);
183 		/* Is a gpio key? */
184 		} else if (key->type & GPIO_KEY) {
185 			/* All pwrkey must register as an interrupt event */
186 			if (key->code == KEY_POWER)
187 				keyval = key_read_gpio_interrupt_event(key);
188 			else
189 				keyval = key_read_gpio_simple_event(key);
190 		} else {
191 			printf("%s: invalid key type!\n", __func__);
192 		}
193 
194 		debug("%s: '%s'(code=%d) is %s\n",
195 		      __func__, key->name, key->code, evt_name[keyval]);
196 
197 		if (keyval == KEY_PRESS_DOWN || keyval == KEY_PRESS_LONG_DOWN)
198 			break;
199 	}
200 
201 	return keyval;
202 }
203 
204 UCLASS_DRIVER(key) = {
205 	.id		= UCLASS_KEY,
206 	.name		= "key",
207 };
208