xref: /rk3399_rockchip-uboot/drivers/input/key-uclass.c (revision f05ce84792cbd2e5573a414010d421eb8fbb7689)
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 	if (!key->parent) {
148 		printf("Err: Can't find key(code=%d) device\n", key->code);
149 		return;
150 	}
151 
152 	key->pre_reloc = dev_read_bool(key->parent, "u-boot,dm-pre-reloc");
153 	list_add_tail(&key->link, &key_list);
154 }
155 
156 static int __key_read(struct input_key *key)
157 {
158 	unsigned int adcval;
159 	int keyval = KEY_NOT_EXIST;
160 	int ret;
161 
162 	/* Is a adc key? */
163 	if (key->type & ADC_KEY) {
164 		ret = adc_channel_single_shot("saradc",
165 					      key->channel, &adcval);
166 		if (ret)
167 			printf("%s: failed to read saradc, ret=%d\n",
168 			       key->name, ret);
169 		else
170 			keyval = key_read_adc_simple_event(key, adcval);
171 	/* Is a gpio key? */
172 	} else if (key->type & GPIO_KEY) {
173 		/* All pwrkey must register as an interrupt event */
174 		if (key->code == KEY_POWER)
175 			keyval = key_read_gpio_interrupt_event(key);
176 		else
177 			keyval = key_read_gpio_simple_event(key);
178 	} else {
179 		printf("%s: invalid key type!\n", __func__);
180 	}
181 
182 	debug("%s: '%s'(code=%d) is %s\n",
183 	      __func__, key->name, key->code, evt_name[keyval]);
184 
185 	return keyval;
186 }
187 
188 int key_read(int code)
189 {
190 	struct udevice *dev;
191 	struct input_key *key;
192 	static int initialized;
193 	int keyval = KEY_NOT_EXIST;
194 
195 	/* Initialize all key drivers */
196 	if (!initialized) {
197 		for (uclass_first_device(UCLASS_KEY, &dev);
198 		     dev;
199 		     uclass_next_device(&dev)) {
200 			debug("%s: have found key driver '%s'\n\n",
201 			      __func__, dev->name);
202 		}
203 	}
204 
205 	/* The key from kernel dtb has higher priority */
206 	debug("Reading key from kernel\n");
207 	list_for_each_entry(key, &key_list, link) {
208 		if (key->pre_reloc || (key->code != code))
209 			continue;
210 
211 		keyval = __key_read(key);
212 		if (key_is_pressed(keyval))
213 			return keyval;
214 	}
215 
216 	/* If not found any key from kernel dtb, reading from U-Boot dtb */
217 	if (keyval == KEY_NOT_EXIST) {
218 		debug("Reading key from U-Boot\n");
219 		list_for_each_entry(key, &key_list, link) {
220 			if (!key->pre_reloc || (key->code != code))
221 				continue;
222 
223 			keyval = __key_read(key);
224 			if (key_is_pressed(keyval))
225 				return keyval;
226 		}
227 	}
228 
229 	return keyval;
230 }
231 
232 UCLASS_DRIVER(key) = {
233 	.id		= UCLASS_KEY,
234 	.name		= "key",
235 };
236