xref: /rk3399_rockchip-uboot/drivers/input/key-uclass.c (revision 9f1dd9df855f3714c02b048e40bf29cb0cae1be1)
1b398a9a7SJoseph Chen /*
2b398a9a7SJoseph Chen  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3b398a9a7SJoseph Chen  *
4b398a9a7SJoseph Chen  * SPDX-License-Identifier:     GPL-2.0+
5b398a9a7SJoseph Chen  */
6b398a9a7SJoseph Chen 
764048c53SJoseph Chen #include <common.h>
864048c53SJoseph Chen #include <adc.h>
9b398a9a7SJoseph Chen #include <dm.h>
10b398a9a7SJoseph Chen #include <key.h>
1164048c53SJoseph Chen 
1264048c53SJoseph Chen static LIST_HEAD(key_list);
13b398a9a7SJoseph Chen 
14adba3792SJoseph Chen const char *evt_name[] = {
15adba3792SJoseph Chen 	"Not down",
16adba3792SJoseph Chen 	"Down",
17adba3792SJoseph Chen 	"Long down",
18adba3792SJoseph Chen 	"Not exist",
19adba3792SJoseph Chen };
20adba3792SJoseph Chen 
21a2df9606SJoseph Chen static inline uint64_t arch_counter_get_cntpct(void)
22a2df9606SJoseph Chen {
23a2df9606SJoseph Chen 	uint64_t cval = 0;
24a2df9606SJoseph Chen 
25a2df9606SJoseph Chen 	isb();
26a2df9606SJoseph Chen #ifdef CONFIG_ARM64
27a2df9606SJoseph Chen 	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
28a2df9606SJoseph Chen #else
29a2df9606SJoseph Chen 	asm volatile ("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
30a2df9606SJoseph Chen #endif
31a2df9606SJoseph Chen 	return cval;
32a2df9606SJoseph Chen }
33a2df9606SJoseph Chen 
3464048c53SJoseph Chen uint64_t key_timer(uint64_t base)
35a2df9606SJoseph Chen {
36a2df9606SJoseph Chen 	uint64_t cntpct;
37a2df9606SJoseph Chen 
38a2df9606SJoseph Chen 	cntpct = arch_counter_get_cntpct() / 24000UL;
39a2df9606SJoseph Chen 	return (cntpct > base) ? (cntpct - base) : 0;
40a2df9606SJoseph Chen }
41a2df9606SJoseph Chen 
4264048c53SJoseph Chen /*
4364048c53SJoseph Chen  * What's simple and complex event mean?
4464048c53SJoseph Chen  *
4564048c53SJoseph Chen  * simple event:   key press down or none;
4664048c53SJoseph Chen  * complext event: key press down, long down or none;
4764048c53SJoseph Chen  */
4864048c53SJoseph Chen static int key_read_adc_simple_event(struct input_key *key, unsigned int adcval)
49a2df9606SJoseph Chen {
5064048c53SJoseph Chen 	int max, min, margin = 30;
5164048c53SJoseph Chen 	int keyval;
523fb84000SJoseph Chen 
533fb84000SJoseph Chen 	/* Get min, max */
5464048c53SJoseph Chen 	max = key->adcval + margin;
5564048c53SJoseph Chen 	if (key->adcval > margin)
5664048c53SJoseph Chen 		min = key->adcval - margin;
573fb84000SJoseph Chen 	else
5864048c53SJoseph Chen 		min = 0;
593fb84000SJoseph Chen 
60adba3792SJoseph Chen 	debug("%s: '%s' configure adc=%d: range[%d~%d]; hw adcval=%d\n",
61adba3792SJoseph Chen 	      __func__, key->name, key->adcval, min, max, adcval);
6233385721SJoseph Chen 
633fb84000SJoseph Chen 	/* Check */
643fb84000SJoseph Chen 	if ((adcval <= max) && (adcval >= min)) {
6564048c53SJoseph Chen 		keyval = KEY_PRESS_DOWN;
6664048c53SJoseph Chen 		debug("%s key pressed..\n", key->name);
673fb84000SJoseph Chen 	} else {
6864048c53SJoseph Chen 		keyval = KEY_PRESS_NONE;
693fb84000SJoseph Chen 	}
703fb84000SJoseph Chen 
7164048c53SJoseph Chen 	return keyval;
723fb84000SJoseph Chen }
733fb84000SJoseph Chen 
7464048c53SJoseph Chen static int key_read_gpio_simple_event(struct input_key *key)
753fb84000SJoseph Chen {
7664048c53SJoseph Chen 	if (!dm_gpio_is_valid(&key->gpio)) {
7764048c53SJoseph Chen 		printf("%s: invalid gpio\n", key->name);
7864048c53SJoseph Chen 		return KEY_PRESS_NONE;
7964048c53SJoseph Chen 	}
8064048c53SJoseph Chen 
8164048c53SJoseph Chen 	return dm_gpio_get_value(&key->gpio) ? KEY_PRESS_DOWN : KEY_PRESS_NONE;
8264048c53SJoseph Chen }
8364048c53SJoseph Chen 
8464048c53SJoseph Chen static int key_read_gpio_complex_event(struct input_key *key)
8564048c53SJoseph Chen {
8664048c53SJoseph Chen 	int keyval;
873fb84000SJoseph Chen 
883fb84000SJoseph Chen 	debug("%s: %s: up=%llu, down=%llu, delta=%llu\n",
893fb84000SJoseph Chen 	      __func__, key->name, key->up_t, key->down_t,
903fb84000SJoseph Chen 	      key->up_t - key->down_t);
913fb84000SJoseph Chen 
923fb84000SJoseph Chen 	/* Possible this is machine power-on long pressed, so ignore this */
933fb84000SJoseph Chen 	if (key->down_t == 0 && key->up_t != 0) {
9464048c53SJoseph Chen 		keyval = KEY_PRESS_NONE;
953fb84000SJoseph Chen 		goto out;
963fb84000SJoseph Chen 	}
973fb84000SJoseph Chen 
983fb84000SJoseph Chen 	if ((key->up_t > key->down_t) &&
993fb84000SJoseph Chen 	    (key->up_t - key->down_t) >= KEY_LONG_DOWN_MS) {
1003fb84000SJoseph Chen 		key->up_t = 0;
1013fb84000SJoseph Chen 		key->down_t = 0;
10264048c53SJoseph Chen 		keyval = KEY_PRESS_LONG_DOWN;
10364048c53SJoseph Chen 		debug("%s key long pressed..\n", key->name);
1043fb84000SJoseph Chen 	} else if (key->down_t &&
10564048c53SJoseph Chen 		   key_timer(key->down_t) >= KEY_LONG_DOWN_MS) {
1063fb84000SJoseph Chen 		key->up_t = 0;
1073fb84000SJoseph Chen 		key->down_t = 0;
10864048c53SJoseph Chen 		keyval = KEY_PRESS_LONG_DOWN;
10964048c53SJoseph Chen 		debug("%s key long pressed(hold)..\n", key->name);
1103fb84000SJoseph Chen 	} else if ((key->up_t > key->down_t) &&
1113fb84000SJoseph Chen 		   (key->up_t - key->down_t) < KEY_LONG_DOWN_MS) {
1123fb84000SJoseph Chen 		key->up_t = 0;
1133fb84000SJoseph Chen 		key->down_t = 0;
11464048c53SJoseph Chen 		keyval = KEY_PRESS_DOWN;
11564048c53SJoseph Chen 		debug("%s key short pressed..\n", key->name);
11664048c53SJoseph Chen 	/* Possible in charge animation, we enable irq after fuel gauge updated */
11764048c53SJoseph Chen 	} else if (key->up_t && key->down_t && (key->up_t == key->down_t)){
11864048c53SJoseph Chen 		key->up_t = 0;
11964048c53SJoseph Chen 		key->down_t = 0;
12064048c53SJoseph Chen 		keyval = KEY_PRESS_DOWN;
12164048c53SJoseph Chen 		debug("%s key short pressed..\n", key->name);
1223fb84000SJoseph Chen 	} else {
12364048c53SJoseph Chen 		keyval = KEY_PRESS_NONE;
1243fb84000SJoseph Chen 	}
1253fb84000SJoseph Chen 
1263fb84000SJoseph Chen out:
12764048c53SJoseph Chen 	return keyval;
12864048c53SJoseph Chen }
12964048c53SJoseph Chen 
13064048c53SJoseph Chen static int key_read_gpio_interrupt_event(struct input_key *key)
13164048c53SJoseph Chen {
13264048c53SJoseph Chen 	debug("%s: %s\n", __func__, key->name);
13364048c53SJoseph Chen 
13464048c53SJoseph Chen 	return key_read_gpio_complex_event(key);
13564048c53SJoseph Chen }
13664048c53SJoseph Chen 
13764048c53SJoseph Chen int key_is_pressed(int keyval)
13864048c53SJoseph Chen {
13964048c53SJoseph Chen 	return (keyval == KEY_PRESS_DOWN || keyval == KEY_PRESS_LONG_DOWN);
14064048c53SJoseph Chen }
14164048c53SJoseph Chen 
14264048c53SJoseph Chen void key_add(struct input_key *key)
14364048c53SJoseph Chen {
14464048c53SJoseph Chen 	if (!key)
14564048c53SJoseph Chen 		return;
14664048c53SJoseph Chen 
147*9f1dd9dfSJoseph Chen 	if (!key->parent) {
148*9f1dd9dfSJoseph Chen 		printf("Err: Can't find key(code=%d) device\n", key->code);
149*9f1dd9dfSJoseph Chen 		return;
150*9f1dd9dfSJoseph Chen 	}
151*9f1dd9dfSJoseph Chen 
152*9f1dd9dfSJoseph Chen 	key->pre_reloc = dev_read_bool(key->parent, "u-boot,dm-pre-reloc");
15364048c53SJoseph Chen 	list_add_tail(&key->link, &key_list);
15464048c53SJoseph Chen }
15564048c53SJoseph Chen 
156*9f1dd9dfSJoseph Chen static int __key_read(struct input_key *key)
15764048c53SJoseph Chen {
15864048c53SJoseph Chen 	unsigned int adcval;
15964048c53SJoseph Chen 	int keyval = KEY_NOT_EXIST;
160adba3792SJoseph Chen 	int ret;
16164048c53SJoseph Chen 
16264048c53SJoseph Chen 	/* Is a adc key? */
16364048c53SJoseph Chen 	if (key->type & ADC_KEY) {
164adba3792SJoseph Chen 		ret = adc_channel_single_shot("saradc",
165adba3792SJoseph Chen 					      key->channel, &adcval);
16664048c53SJoseph Chen 		if (ret)
16764048c53SJoseph Chen 			printf("%s: failed to read saradc, ret=%d\n",
16864048c53SJoseph Chen 			       key->name, ret);
16964048c53SJoseph Chen 		else
17064048c53SJoseph Chen 			keyval = key_read_adc_simple_event(key, adcval);
17164048c53SJoseph Chen 	/* Is a gpio key? */
17264048c53SJoseph Chen 	} else if (key->type & GPIO_KEY) {
17364048c53SJoseph Chen 		/* All pwrkey must register as an interrupt event */
174adba3792SJoseph Chen 		if (key->code == KEY_POWER)
17564048c53SJoseph Chen 			keyval = key_read_gpio_interrupt_event(key);
176adba3792SJoseph Chen 		else
17764048c53SJoseph Chen 			keyval = key_read_gpio_simple_event(key);
17864048c53SJoseph Chen 	} else {
17964048c53SJoseph Chen 		printf("%s: invalid key type!\n", __func__);
18064048c53SJoseph Chen 	}
18164048c53SJoseph Chen 
182adba3792SJoseph Chen 	debug("%s: '%s'(code=%d) is %s\n",
183adba3792SJoseph Chen 	      __func__, key->name, key->code, evt_name[keyval]);
18464048c53SJoseph Chen 
185*9f1dd9dfSJoseph Chen 	return keyval;
186*9f1dd9dfSJoseph Chen }
187*9f1dd9dfSJoseph Chen 
188*9f1dd9dfSJoseph Chen int key_read(int code)
189*9f1dd9dfSJoseph Chen {
190*9f1dd9dfSJoseph Chen 	struct udevice *dev;
191*9f1dd9dfSJoseph Chen 	struct input_key *key;
192*9f1dd9dfSJoseph Chen 	static int initialized;
193*9f1dd9dfSJoseph Chen 	int keyval = KEY_NOT_EXIST;
194*9f1dd9dfSJoseph Chen 
195*9f1dd9dfSJoseph Chen 	/* Initialize all key drivers */
196*9f1dd9dfSJoseph Chen 	if (!initialized) {
197*9f1dd9dfSJoseph Chen 		for (uclass_first_device(UCLASS_KEY, &dev);
198*9f1dd9dfSJoseph Chen 		     dev;
199*9f1dd9dfSJoseph Chen 		     uclass_next_device(&dev)) {
200*9f1dd9dfSJoseph Chen 			debug("%s: have found key driver '%s'\n\n",
201*9f1dd9dfSJoseph Chen 			      __func__, dev->name);
202*9f1dd9dfSJoseph Chen 		}
203*9f1dd9dfSJoseph Chen 	}
204*9f1dd9dfSJoseph Chen 
205*9f1dd9dfSJoseph Chen 	/* The key from kernel dtb has higher priority */
206*9f1dd9dfSJoseph Chen 	debug("Reading key from kernel\n");
207*9f1dd9dfSJoseph Chen 	list_for_each_entry(key, &key_list, link) {
208*9f1dd9dfSJoseph Chen 		if (key->pre_reloc || (key->code != code))
209*9f1dd9dfSJoseph Chen 			continue;
210*9f1dd9dfSJoseph Chen 
211*9f1dd9dfSJoseph Chen 		keyval = __key_read(key);
212*9f1dd9dfSJoseph Chen 		if (key_is_pressed(keyval))
213*9f1dd9dfSJoseph Chen 			return keyval;
214*9f1dd9dfSJoseph Chen 	}
215*9f1dd9dfSJoseph Chen 
216*9f1dd9dfSJoseph Chen 	/* If not found any key from kernel dtb, reading from U-Boot dtb */
217*9f1dd9dfSJoseph Chen 	if (keyval == KEY_NOT_EXIST) {
218*9f1dd9dfSJoseph Chen 		debug("Reading key from U-Boot\n");
219*9f1dd9dfSJoseph Chen 		list_for_each_entry(key, &key_list, link) {
220*9f1dd9dfSJoseph Chen 			if (!key->pre_reloc || (key->code != code))
221*9f1dd9dfSJoseph Chen 				continue;
222*9f1dd9dfSJoseph Chen 
223*9f1dd9dfSJoseph Chen 			keyval = __key_read(key);
224*9f1dd9dfSJoseph Chen 			if (key_is_pressed(keyval))
225*9f1dd9dfSJoseph Chen 				return keyval;
226*9f1dd9dfSJoseph Chen 		}
227adba3792SJoseph Chen 	}
228adba3792SJoseph Chen 
22964048c53SJoseph Chen 	return keyval;
2303fb84000SJoseph Chen }
2313fb84000SJoseph Chen 
232b398a9a7SJoseph Chen UCLASS_DRIVER(key) = {
233b398a9a7SJoseph Chen 	.id		= UCLASS_KEY,
234b398a9a7SJoseph Chen 	.name		= "key",
235b398a9a7SJoseph Chen };
236