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