xref: /rk3399_rockchip-uboot/drivers/input/spl_adc_key.c (revision a6c9ff8691383a19143bc7d99d254cffe997e9a3)
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 
adc_raw_to_mV(struct udevice * dev,unsigned int raw,int * mV)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 
key_read(int code)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