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