1abedddcfSJoseph Chen /* 2abedddcfSJoseph Chen * (C) Copyright 2020 Rockchip Electronics Co., Ltd 3abedddcfSJoseph Chen * 4abedddcfSJoseph Chen * SPDX-License-Identifier: GPL-2.0+ 5abedddcfSJoseph Chen */ 6abedddcfSJoseph Chen 7abedddcfSJoseph Chen #include <common.h> 8abedddcfSJoseph Chen #include <adc.h> 9*ce0e3b1eSJoseph Chen #include <div64.h> 10abedddcfSJoseph Chen #include <fdtdec.h> 11*ce0e3b1eSJoseph Chen #include <dm/uclass.h> 12abedddcfSJoseph Chen 13abedddcfSJoseph Chen DECLARE_GLOBAL_DATA_PTR; 14abedddcfSJoseph Chen 15*ce0e3b1eSJoseph Chen static int adc_raw_to_mV(struct udevice *dev, unsigned int raw, int *mV) 16*ce0e3b1eSJoseph Chen { 17*ce0e3b1eSJoseph Chen unsigned int data_mask; 18*ce0e3b1eSJoseph Chen int ret, vref = 1800000; 19*ce0e3b1eSJoseph Chen u64 raw64 = raw; 20*ce0e3b1eSJoseph Chen 21*ce0e3b1eSJoseph Chen ret = adc_data_mask(dev, &data_mask); 22*ce0e3b1eSJoseph Chen if (ret) 23*ce0e3b1eSJoseph Chen return ret; 24*ce0e3b1eSJoseph Chen 25*ce0e3b1eSJoseph Chen raw64 *= vref; 26*ce0e3b1eSJoseph Chen do_div(raw64, data_mask); 27*ce0e3b1eSJoseph Chen *mV = raw64; 28*ce0e3b1eSJoseph Chen 29*ce0e3b1eSJoseph Chen return 0; 30*ce0e3b1eSJoseph Chen } 31*ce0e3b1eSJoseph Chen 32abedddcfSJoseph Chen int key_read(int code) 33abedddcfSJoseph Chen { 34abedddcfSJoseph Chen const void *fdt_blob = gd->fdt_blob; 35*ce0e3b1eSJoseph Chen struct udevice *dev; 36abedddcfSJoseph Chen int adc_node, offset; 37*ce0e3b1eSJoseph Chen int t, down_threshold = -1, up_threshold; 38*ce0e3b1eSJoseph Chen int ret, num = 0, volt_margin = 150000; /* will be div 2 */ 39*ce0e3b1eSJoseph Chen int mV, cd, voltage = -1; 40abedddcfSJoseph Chen int min, max; 41*ce0e3b1eSJoseph Chen u32 chn[2], adc; 42*ce0e3b1eSJoseph Chen 43*ce0e3b1eSJoseph Chen ret = uclass_get_device_by_name(UCLASS_ADC, "saradc", &dev); 44*ce0e3b1eSJoseph Chen if (ret) { 45*ce0e3b1eSJoseph Chen debug("No saradc device, ret=%d\n", ret); 46*ce0e3b1eSJoseph Chen return 0; 47*ce0e3b1eSJoseph Chen } 48*ce0e3b1eSJoseph Chen 49abedddcfSJoseph Chen adc_node = fdt_node_offset_by_compatible(fdt_blob, 0, "adc-keys"); 50abedddcfSJoseph Chen if (adc_node < 0) { 51abedddcfSJoseph Chen debug("No 'adc-keys' node, ret=%d\n", adc_node); 52abedddcfSJoseph Chen return 0; 53abedddcfSJoseph Chen } 54abedddcfSJoseph Chen 55abedddcfSJoseph Chen ret = fdtdec_get_int_array(fdt_blob, adc_node, "io-channels", 56abedddcfSJoseph Chen chn, ARRAY_SIZE(chn)); 57abedddcfSJoseph Chen if (ret) { 58abedddcfSJoseph Chen debug("Can't read 'io-channels', ret=%d\n", ret); 59abedddcfSJoseph Chen return 0; 60abedddcfSJoseph Chen } 61abedddcfSJoseph Chen 62*ce0e3b1eSJoseph Chen up_threshold = fdtdec_get_int(fdt_blob, adc_node, 63*ce0e3b1eSJoseph Chen "keyup-threshold-microvolt", -ENODATA); 64*ce0e3b1eSJoseph Chen if (up_threshold < 0) { 65abedddcfSJoseph Chen debug("Can't read 'keyup-threshold-microvolt'\n"); 66abedddcfSJoseph Chen return 0; 67abedddcfSJoseph Chen } 68abedddcfSJoseph Chen 69*ce0e3b1eSJoseph Chen /* find the expected key-code */ 70*ce0e3b1eSJoseph Chen for (offset = fdt_first_subnode(fdt_blob, adc_node); 71*ce0e3b1eSJoseph Chen offset >= 0; 72*ce0e3b1eSJoseph Chen offset = fdt_next_subnode(fdt_blob, offset)) { 73*ce0e3b1eSJoseph Chen cd = fdtdec_get_int(fdt_blob, offset, "linux,code", -ENODATA); 74*ce0e3b1eSJoseph Chen if (cd < 0) { 75*ce0e3b1eSJoseph Chen debug("Can't read 'linux,code', ret=%d\n", cd); 76*ce0e3b1eSJoseph Chen return 0; 77*ce0e3b1eSJoseph Chen } 78*ce0e3b1eSJoseph Chen 79*ce0e3b1eSJoseph Chen if (cd == code) { 80*ce0e3b1eSJoseph Chen voltage = fdtdec_get_int(fdt_blob, offset, 81*ce0e3b1eSJoseph Chen "press-threshold-microvolt", -ENODATA); 82*ce0e3b1eSJoseph Chen if (voltage < 0) { 83*ce0e3b1eSJoseph Chen debug("Can't read 'press-threshold-microvolt'\n"); 84*ce0e3b1eSJoseph Chen return 0; 85*ce0e3b1eSJoseph Chen } 86*ce0e3b1eSJoseph Chen break; 87*ce0e3b1eSJoseph Chen } 88*ce0e3b1eSJoseph Chen } 89*ce0e3b1eSJoseph Chen 90*ce0e3b1eSJoseph Chen if (voltage < 0) 91*ce0e3b1eSJoseph Chen return 0; 92abedddcfSJoseph Chen 93abedddcfSJoseph Chen for (offset = fdt_first_subnode(fdt_blob, adc_node); 94abedddcfSJoseph Chen offset >= 0; 95abedddcfSJoseph Chen offset = fdt_next_subnode(fdt_blob, offset)) { 96*ce0e3b1eSJoseph Chen t = fdtdec_get_int(fdt_blob, offset, 97*ce0e3b1eSJoseph Chen "press-threshold-microvolt", -ENODATA); 98*ce0e3b1eSJoseph Chen if (t < 0) { 99abedddcfSJoseph Chen debug("Can't read 'press-threshold-microvolt'\n"); 100abedddcfSJoseph Chen return 0; 101abedddcfSJoseph Chen } 102abedddcfSJoseph Chen 103*ce0e3b1eSJoseph Chen if (t > voltage && t < up_threshold) 104*ce0e3b1eSJoseph Chen up_threshold = t; 105*ce0e3b1eSJoseph Chen else if (t < voltage && t > down_threshold) 106*ce0e3b1eSJoseph Chen down_threshold = t; 107*ce0e3b1eSJoseph Chen num++; 108*ce0e3b1eSJoseph Chen } 109*ce0e3b1eSJoseph Chen 110*ce0e3b1eSJoseph Chen /* although one node only, it doesn't mean only one key on hardware */ 111*ce0e3b1eSJoseph Chen if (num == 1) { 112*ce0e3b1eSJoseph Chen down_threshold = voltage - volt_margin; 113*ce0e3b1eSJoseph Chen up_threshold = voltage + volt_margin; 114*ce0e3b1eSJoseph Chen } 115*ce0e3b1eSJoseph Chen 116*ce0e3b1eSJoseph Chen /* 117*ce0e3b1eSJoseph Chen * Define the voltage range such that the button is only pressed 118*ce0e3b1eSJoseph Chen * when the voltage is closest to its own press-threshold-microvolt 119*ce0e3b1eSJoseph Chen */ 120*ce0e3b1eSJoseph Chen if (down_threshold < 0) 121*ce0e3b1eSJoseph Chen min = 0; 122*ce0e3b1eSJoseph Chen else 123*ce0e3b1eSJoseph Chen min = down_threshold + (voltage - down_threshold) / 2; 124*ce0e3b1eSJoseph Chen 125*ce0e3b1eSJoseph Chen max = voltage + (up_threshold - voltage) / 2; 126*ce0e3b1eSJoseph Chen 127*ce0e3b1eSJoseph Chen /* now, read key status */ 128*ce0e3b1eSJoseph Chen ret = adc_channel_single_shot("saradc", chn[1], &adc); 129abedddcfSJoseph Chen if (ret) { 130*ce0e3b1eSJoseph Chen debug("Failed to read adc%d, ret=%d\n", chn[1], ret); 131abedddcfSJoseph Chen return 0; 132abedddcfSJoseph Chen } 133abedddcfSJoseph Chen 134*ce0e3b1eSJoseph Chen ret = adc_raw_to_mV(dev, adc, &mV); 135*ce0e3b1eSJoseph Chen if (ret) { 136*ce0e3b1eSJoseph Chen debug("Failed to convert adc to mV, ret=%d\n", ret); 137abedddcfSJoseph Chen return 0; 138abedddcfSJoseph Chen } 139*ce0e3b1eSJoseph Chen 140*ce0e3b1eSJoseph Chen debug("key[%d] <%d, %d, %d>: adc=%d -> mV=%d\n", 141*ce0e3b1eSJoseph Chen code, min, voltage, max, adc, mV); 142*ce0e3b1eSJoseph Chen 143*ce0e3b1eSJoseph Chen return (mV <= max && mV >= min); 144*ce0e3b1eSJoseph Chen } 145*ce0e3b1eSJoseph Chen 146