xref: /rk3399_rockchip-uboot/drivers/input/key-uclass.c (revision c2e7a0d48362ac5b8288265bb0bcebd6dc80e187)
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 #include <dm/lists.h>
12 #include <irq-generic.h>
13 
14 #define KEY_WARN(fmt, args...)	printf("Key Warn: "fmt, ##args)
15 #define KEY_ERR(fmt, args...)	printf("Key Error: "fmt, ##args)
16 #define KEY_DBG(fmt, args...)	 debug("Key Debug: "fmt, ##args)
17 
18 static inline uint64_t arch_counter_get_cntpct(void)
19 {
20 	uint64_t cval = 0;
21 
22 	isb();
23 #ifdef CONFIG_ARM64
24 	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
25 #else
26 	asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
27 #endif
28 	return cval;
29 }
30 
31 uint64_t key_timer(uint64_t base)
32 {
33 	uint64_t cntpct;
34 
35 	cntpct = arch_counter_get_cntpct() / 24000UL;
36 	return (cntpct > base) ? (cntpct - base) : 0;
37 }
38 
39 static int key_adc_event(struct dm_key_uclass_platdata *uc_key, int adcval)
40 {
41 	return (adcval <= uc_key->max && adcval >= uc_key->min) ?
42 		KEY_PRESS_DOWN : KEY_PRESS_NONE;
43 }
44 
45 static int key_gpio_event(struct dm_key_uclass_platdata *uc_key)
46 {
47 	if (!dm_gpio_is_valid(&uc_key->gpio)) {
48 		KEY_ERR("'%s' Invalid gpio\n", uc_key->name);
49 		return KEY_PRESS_NONE;
50 	}
51 
52 	return dm_gpio_get_value(&uc_key->gpio) ?
53 	       KEY_PRESS_DOWN : KEY_PRESS_NONE;
54 }
55 
56 static int key_gpio_interrupt_event(struct dm_key_uclass_platdata *uc_key)
57 {
58 	int event;
59 
60 	debug("%s: %s: up=%llu, down=%llu, delta=%llu\n",
61 	      __func__, uc_key->name, uc_key->rise_ms, uc_key->fall_ms,
62 	      uc_key->rise_ms - uc_key->fall_ms);
63 
64 	/* Possible this is machine power-on long pressed, so ignore this */
65 	if (uc_key->fall_ms == 0 && uc_key->rise_ms != 0) {
66 		event = KEY_PRESS_NONE;
67 		goto out;
68 	}
69 
70 	if ((uc_key->rise_ms > uc_key->fall_ms) &&
71 	    (uc_key->rise_ms - uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
72 		uc_key->rise_ms = 0;
73 		uc_key->fall_ms = 0;
74 		event = KEY_PRESS_LONG_DOWN;
75 		KEY_DBG("%s key long pressed..\n", uc_key->name);
76 	} else if (uc_key->fall_ms &&
77 		   key_timer(uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
78 		uc_key->rise_ms = 0;
79 		uc_key->fall_ms = 0;
80 		event = KEY_PRESS_LONG_DOWN;
81 		KEY_DBG("%s key long pressed(hold)..\n", uc_key->name);
82 	} else if ((uc_key->rise_ms > uc_key->fall_ms) &&
83 		   (uc_key->rise_ms - uc_key->fall_ms) < KEY_LONG_DOWN_MS) {
84 		uc_key->rise_ms = 0;
85 		uc_key->fall_ms = 0;
86 		event = KEY_PRESS_DOWN;
87 		KEY_DBG("%s key short pressed..\n", uc_key->name);
88 	/* Possible in charge animation, we enable irq after fuel gauge updated */
89 	} else if (uc_key->rise_ms && uc_key->fall_ms &&
90 		   (uc_key->rise_ms == uc_key->fall_ms)) {
91 		uc_key->rise_ms = 0;
92 		uc_key->fall_ms = 0;
93 		event = KEY_PRESS_DOWN;
94 		KEY_DBG("%s key short pressed..\n", uc_key->name);
95 	} else {
96 		event = KEY_PRESS_NONE;
97 	}
98 
99 out:
100 	return event;
101 }
102 
103 int key_is_pressed(int event)
104 {
105 	return (event == KEY_PRESS_DOWN || event == KEY_PRESS_LONG_DOWN);
106 }
107 
108 static int key_core_read(struct dm_key_uclass_platdata *uc_key)
109 {
110 	unsigned int adcval;
111 
112 	if (uc_key->type == ADC_KEY) {
113 		if (adc_channel_single_shot("saradc",
114 					    uc_key->channel, &adcval)) {
115 			KEY_ERR("%s failed to read saradc\n", uc_key->name);
116 			return KEY_NOT_EXIST;
117 		}
118 
119 		return key_adc_event(uc_key, adcval);
120 	}
121 
122 	return (uc_key->code == KEY_POWER) ?
123 		key_gpio_interrupt_event(uc_key) :
124 		key_gpio_event(uc_key);
125 }
126 
127 int key_read(int code)
128 {
129 	struct dm_key_uclass_platdata *uc_key;
130 	struct udevice *dev;
131 	struct uclass *uc;
132 	bool allow_pre_reloc = false;
133 	int ret, event = KEY_NOT_EXIST;
134 
135 	ret = uclass_get(UCLASS_KEY, &uc);
136 	if (ret)
137 		return ret;
138 
139 try_again:
140 	for (uclass_first_device(UCLASS_KEY, &dev);
141 	     dev;
142 	     uclass_next_device(&dev)) {
143 		uc_key = dev_get_uclass_platdata(dev);
144 
145 		if (!allow_pre_reloc && uc_key->pre_reloc)
146 			continue;
147 
148 		if (uc_key->code != code)
149 			continue;
150 
151 		event = key_core_read(uc_key);
152 		if (key_is_pressed(event))
153 			return event;
154 	}
155 
156 	/* If not find valid key node from kernel, try from u-boot */
157 	if (event == KEY_NOT_EXIST && !allow_pre_reloc) {
158 		allow_pre_reloc = true;
159 		goto try_again;
160 	}
161 
162 	return event;
163 }
164 
165 #ifdef CONFIG_IRQ
166 static void gpio_irq_handler(int irq, void *data)
167 {
168 	struct udevice *dev = data;
169 	struct dm_key_uclass_platdata *uc_key = dev_get_uclass_platdata(dev);
170 
171 	if (uc_key->irq != irq)
172 		return;
173 
174 	if (uc_key->irq_thread) {
175 		uc_key->irq_thread(irq, data);
176 	} else {
177 		if (irq_get_gpio_level(irq)) {
178 			uc_key->rise_ms = key_timer(0);
179 			KEY_DBG("%s: key dn: %llu ms\n",
180 				uc_key->name, uc_key->fall_ms);
181 		} else {
182 			uc_key->fall_ms = key_timer(0);
183 			KEY_DBG("%s: key up: %llu ms\n",
184 				uc_key->name, uc_key->rise_ms);
185 		}
186 
187 		/* Must delay */
188 		mdelay(10);
189 		irq_revert_irq_type(irq);
190 	}
191 }
192 #endif
193 
194 int key_bind_children(struct udevice *dev, const char *drv_name)
195 {
196 	const char *name;
197 	ofnode node;
198 	int ret;
199 
200 	dev_for_each_subnode(node, dev) {
201 		/*
202 		 * If this node has "compatible" property, this is not
203 		 * a amp subnode, but a normal device. skip.
204 		 */
205 		ofnode_get_property(node, "compatible", &ret);
206 		if (ret >= 0)
207 			continue;
208 
209 		if (ret != -FDT_ERR_NOTFOUND)
210 			return ret;
211 
212 		name = ofnode_get_name(node);
213 		if (!name)
214 			return -EINVAL;
215 		ret = device_bind_driver_to_node(dev, drv_name, name,
216 						 node, NULL);
217 		if (ret)
218 			return ret;
219 	}
220 
221 	return 0;
222 }
223 
224 static int key_post_probe(struct udevice *dev)
225 {
226 	struct dm_key_uclass_platdata *uc_key;
227 	int margin = 30;
228 	int ret;
229 
230 	uc_key = dev_get_uclass_platdata(dev);
231 	if (!uc_key)
232 		return -ENXIO;
233 
234 	/* True from U-Boot key node */
235 	uc_key->pre_reloc = dev_read_bool(dev, "u-boot,dm-pre-reloc");
236 
237 	if (uc_key->type == ADC_KEY) {
238 		uc_key->max = uc_key->adcval + margin;
239 		uc_key->min = uc_key->adcval > margin ?
240 					uc_key->adcval - margin : 0;
241 	} else {
242 		if (uc_key->code == KEY_POWER) {
243 #ifdef CONFIG_IRQ
244 			int irq;
245 
246 			irq = phandle_gpio_to_irq(uc_key->gpios[0],
247 						  uc_key->gpios[1]);
248 			if (irq < 0) {
249 				KEY_ERR("%s: failed to request irq, ret=%d\n",
250 					uc_key->name, irq);
251 				return irq;
252 			}
253 
254 			if (uc_key->code != KEY_POWER && uc_key->irq_thread) {
255 				KEY_WARN("%s: only power key can request irq thread\n",
256 					 uc_key->name);
257 				return -EINVAL;
258 			}
259 
260 			uc_key->irq = irq;
261 			irq_install_handler(irq, gpio_irq_handler, dev);
262 			irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
263 			irq_handler_enable(irq);
264 #else
265 			KEY_WARN("%s: no IRQ framework available\n", uc_key->name);
266 #endif
267 		} else {
268 			ret = gpio_request_by_name(dev, "gpios", 0,
269 						   &uc_key->gpio, GPIOD_IS_IN);
270 			if (ret) {
271 				KEY_ERR("%s: failed to request gpio, ret=%d\n",
272 					uc_key->name, ret);
273 				return ret;
274 			}
275 		}
276 	}
277 
278 #ifdef DEBUG
279 	printf("[%s] (%s, %s, %s):\n", uc_key->name,
280 	       uc_key->type == ADC_KEY ? "ADC" : "GPIO",
281 	       uc_key->pre_reloc ? "U-Boot" : "Kernel",
282 	       dev->parent->name);
283 
284 	if (uc_key->type == ADC_KEY) {
285 		printf("    adcval: %d (%d, %d)\n", uc_key->adcval,
286 		       uc_key->min, uc_key->max);
287 		printf("   channel: %d\n\n", uc_key->channel);
288 	} else {
289 		const char *gpio_name =
290 		     ofnode_get_name(ofnode_get_by_phandle(uc_key->gpios[0]));
291 
292 		printf("       irq: %d\n", uc_key->irq);
293 		printf("   gpio[0]: %s\n", gpio_name);
294 		printf("   gpio[1]: %d\n\n", uc_key->gpios[1]);
295 	}
296 #endif
297 
298 	return 0;
299 }
300 
301 UCLASS_DRIVER(key) = {
302 	.id		= UCLASS_KEY,
303 	.name		= "key",
304 	.post_probe	= key_post_probe,
305 	.per_device_platdata_auto_alloc_size =
306 			sizeof(struct dm_key_uclass_platdata),
307 };
308