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