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