.. | .. |
---|
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 | + |
---|