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