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 ret = uclass_get_device_by_name(UCLASS_ADC, "adc", &dev); 46 if (ret) { 47 debug("No saradc device, ret=%d\n", ret); 48 return 0; 49 } 50 51 adc_node = fdt_node_offset_by_compatible(fdt_blob, 0, "adc-keys"); 52 if (adc_node < 0) { 53 debug("No 'adc-keys' node, ret=%d\n", adc_node); 54 return 0; 55 } 56 57 ret = fdtdec_get_int_array(fdt_blob, adc_node, "io-channels", 58 chn, ARRAY_SIZE(chn)); 59 if (ret) { 60 debug("Can't read 'io-channels', ret=%d\n", ret); 61 return 0; 62 } 63 64 up_threshold = fdtdec_get_int(fdt_blob, adc_node, 65 "keyup-threshold-microvolt", -ENODATA); 66 if (up_threshold < 0) { 67 debug("Can't read 'keyup-threshold-microvolt'\n"); 68 return 0; 69 } 70 71 /* find the expected key-code */ 72 for (offset = fdt_first_subnode(fdt_blob, adc_node); 73 offset >= 0; 74 offset = fdt_next_subnode(fdt_blob, offset)) { 75 cd = fdtdec_get_int(fdt_blob, offset, "linux,code", -ENODATA); 76 if (cd < 0) { 77 debug("Can't read 'linux,code', ret=%d\n", cd); 78 return 0; 79 } 80 81 if (cd == code) { 82 voltage = fdtdec_get_int(fdt_blob, offset, 83 "press-threshold-microvolt", -ENODATA); 84 if (voltage < 0) { 85 debug("Can't read 'press-threshold-microvolt'\n"); 86 return 0; 87 } 88 break; 89 } 90 } 91 92 if (voltage < 0) 93 return 0; 94 95 for (offset = fdt_first_subnode(fdt_blob, adc_node); 96 offset >= 0; 97 offset = fdt_next_subnode(fdt_blob, offset)) { 98 t = fdtdec_get_int(fdt_blob, offset, 99 "press-threshold-microvolt", -ENODATA); 100 if (t < 0) { 101 debug("Can't read 'press-threshold-microvolt'\n"); 102 return 0; 103 } 104 105 if (t > voltage && t < up_threshold) 106 up_threshold = t; 107 else if (t < voltage && t > down_threshold) 108 down_threshold = t; 109 num++; 110 } 111 112 /* although one node only, it doesn't mean only one key on hardware */ 113 if (num == 1) { 114 down_threshold = voltage - volt_margin; 115 up_threshold = voltage + volt_margin; 116 } 117 118 /* 119 * Define the voltage range such that the button is only pressed 120 * when the voltage is closest to its own press-threshold-microvolt 121 */ 122 if (down_threshold < 0) 123 min = 0; 124 else 125 min = down_threshold + (voltage - down_threshold) / 2; 126 127 max = voltage + (up_threshold - voltage) / 2; 128 129 /* now, read key status */ 130 ret = adc_channel_single_shot("saradc", chn[1], &adc); 131 if (ret) 132 ret = adc_channel_single_shot("adc", chn[1], &adc); 133 if (ret) { 134 debug("Failed to read adc%d, ret=%d\n", chn[1], ret); 135 return 0; 136 } 137 138 ret = adc_raw_to_mV(dev, adc, &mV); 139 if (ret) { 140 debug("Failed to convert adc to mV, ret=%d\n", ret); 141 return 0; 142 } 143 144 debug("key[%d] <%d, %d, %d>: adc=%d -> mV=%d\n", 145 code, min, voltage, max, adc, mV); 146 147 return (mV <= max && mV >= min); 148 } 149 150