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