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