| .. | .. |
|---|
| 6 | 6 | |
|---|
| 7 | 7 | #include <common.h> |
|---|
| 8 | 8 | #include <adc.h> |
|---|
| 9 | +#include <div64.h> |
|---|
| 9 | 10 | #include <fdtdec.h> |
|---|
| 11 | +#include <dm/uclass.h> |
|---|
| 10 | 12 | |
|---|
| 11 | 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 | +} |
|---|
| 12 | 31 | |
|---|
| 13 | 32 | int key_read(int code) |
|---|
| 14 | 33 | { |
|---|
| 15 | 34 | const void *fdt_blob = gd->fdt_blob; |
|---|
| 35 | + struct udevice *dev; |
|---|
| 16 | 36 | int adc_node, offset; |
|---|
| 17 | | - int cd, channel, adc; |
|---|
| 18 | | - int ret, vref, mv; |
|---|
| 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; |
|---|
| 19 | 40 | int min, max; |
|---|
| 20 | | - int margin; |
|---|
| 21 | | - int range; |
|---|
| 22 | | - uint val; |
|---|
| 23 | | - u32 chn[2]; |
|---|
| 24 | | -#ifdef CONFIG_SARADC_ROCKCHIP_V2 |
|---|
| 25 | | - range = 4096; /* 12-bit adc */ |
|---|
| 26 | | - margin = 120; |
|---|
| 27 | | -#else |
|---|
| 28 | | - range = 1024; /* 10-bit adc */ |
|---|
| 29 | | - margin = 30; |
|---|
| 30 | | -#endif |
|---|
| 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 | + |
|---|
| 31 | 49 | adc_node = fdt_node_offset_by_compatible(fdt_blob, 0, "adc-keys"); |
|---|
| 32 | 50 | if (adc_node < 0) { |
|---|
| 33 | 51 | debug("No 'adc-keys' node, ret=%d\n", adc_node); |
|---|
| .. | .. |
|---|
| 41 | 59 | return 0; |
|---|
| 42 | 60 | } |
|---|
| 43 | 61 | |
|---|
| 44 | | - vref = fdtdec_get_int(fdt_blob, adc_node, |
|---|
| 45 | | - "keyup-threshold-microvolt", -1); |
|---|
| 46 | | - if (vref < 0) { |
|---|
| 62 | + up_threshold = fdtdec_get_int(fdt_blob, adc_node, |
|---|
| 63 | + "keyup-threshold-microvolt", -ENODATA); |
|---|
| 64 | + if (up_threshold < 0) { |
|---|
| 47 | 65 | debug("Can't read 'keyup-threshold-microvolt'\n"); |
|---|
| 48 | 66 | return 0; |
|---|
| 49 | 67 | } |
|---|
| 50 | 68 | |
|---|
| 51 | | - channel = chn[1]; |
|---|
| 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; |
|---|
| 52 | 92 | |
|---|
| 53 | 93 | for (offset = fdt_first_subnode(fdt_blob, adc_node); |
|---|
| 54 | 94 | offset >= 0; |
|---|
| 55 | 95 | offset = fdt_next_subnode(fdt_blob, offset)) { |
|---|
| 56 | | - cd = fdtdec_get_int(fdt_blob, offset, "linux,code", -1); |
|---|
| 57 | | - if (cd == code) { |
|---|
| 58 | | - mv = fdtdec_get_int(fdt_blob, offset, |
|---|
| 59 | | - "press-threshold-microvolt", -1); |
|---|
| 60 | | - if (mv < 0) { |
|---|
| 61 | | - debug("Can't read 'press-threshold-microvolt'\n"); |
|---|
| 62 | | - return 0; |
|---|
| 63 | | - } |
|---|
| 64 | | - |
|---|
| 65 | | - adc = mv / (vref / range); |
|---|
| 66 | | - max = adc + margin; |
|---|
| 67 | | - min = adc > margin ? adc - margin : 0; |
|---|
| 68 | | - ret = adc_channel_single_shot("saradc", channel, &val); |
|---|
| 69 | | - if (ret) { |
|---|
| 70 | | - debug("Failed to read adc%d, ret=%d\n", |
|---|
| 71 | | - channel, ret); |
|---|
| 72 | | - return 0; |
|---|
| 73 | | - } |
|---|
| 74 | | - |
|---|
| 75 | | - return (val >= min && val <= max); |
|---|
| 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; |
|---|
| 76 | 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++; |
|---|
| 77 | 108 | } |
|---|
| 78 | 109 | |
|---|
| 79 | | - return 0; |
|---|
| 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); |
|---|
| 80 | 144 | } |
|---|
| 145 | + |
|---|