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