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