xref: /rk3399_rockchip-uboot/drivers/input/adc_key.c (revision 68ed833817dbfd84dd9abe87c046b4573a71be9b)
1*68ed8338SJoseph Chen /*
2*68ed8338SJoseph Chen  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3*68ed8338SJoseph Chen  *
4*68ed8338SJoseph Chen  * SPDX-License-Identifier:     GPL-2.0+
5*68ed8338SJoseph Chen  */
6*68ed8338SJoseph Chen 
7*68ed8338SJoseph Chen #include <dm.h>
8*68ed8338SJoseph Chen #include <dm/read.h>
9*68ed8338SJoseph Chen #include <adc.h>
10*68ed8338SJoseph Chen #include <common.h>
11*68ed8338SJoseph Chen #include <console.h>
12*68ed8338SJoseph Chen #include <errno.h>
13*68ed8338SJoseph Chen #include <fdtdec.h>
14*68ed8338SJoseph Chen #include <malloc.h>
15*68ed8338SJoseph Chen #include <key.h>
16*68ed8338SJoseph Chen #include <linux/input.h>
17*68ed8338SJoseph Chen 
18*68ed8338SJoseph Chen #define ADC_MARGIN		30
19*68ed8338SJoseph Chen #define MAX_KEY_NR		10
20*68ed8338SJoseph Chen 
21*68ed8338SJoseph Chen struct adc_key_priv {
22*68ed8338SJoseph Chen 	u32 key_nr;
23*68ed8338SJoseph Chen };
24*68ed8338SJoseph Chen 
25*68ed8338SJoseph Chen static int adc_keys_ofdata_to_platdata(struct udevice *dev)
26*68ed8338SJoseph Chen {
27*68ed8338SJoseph Chen 	struct adc_key_priv *priv = dev_get_priv(dev);
28*68ed8338SJoseph Chen 	struct input_key *key = dev_get_platdata(dev);
29*68ed8338SJoseph Chen 	u32 adc_channels[2], i = 0, microvolt;
30*68ed8338SJoseph Chen 	int vref, err;
31*68ed8338SJoseph Chen 	ofnode node;
32*68ed8338SJoseph Chen 
33*68ed8338SJoseph Chen 	/* Get vref */
34*68ed8338SJoseph Chen 	vref = dev_read_u32_default(dev, "keyup-threshold-microvolt", -1);
35*68ed8338SJoseph Chen 	if (vref < 0) {
36*68ed8338SJoseph Chen 		printf("failed to read 'keyup-threshold-microvolt', ret=%d\n",
37*68ed8338SJoseph Chen 		       vref);
38*68ed8338SJoseph Chen 		return -EINVAL;
39*68ed8338SJoseph Chen 	}
40*68ed8338SJoseph Chen 
41*68ed8338SJoseph Chen 	/* Get IO channel */
42*68ed8338SJoseph Chen 	err = dev_read_u32_array(dev, "io-channels", adc_channels, 2);
43*68ed8338SJoseph Chen 	if (err) {
44*68ed8338SJoseph Chen 		printf("failed to read 'io-channels' of %s key, ret=%d\n",
45*68ed8338SJoseph Chen 		       key->name, err);
46*68ed8338SJoseph Chen 		return -EINVAL;
47*68ed8338SJoseph Chen 	}
48*68ed8338SJoseph Chen 
49*68ed8338SJoseph Chen 	/* Parse every adc key data */
50*68ed8338SJoseph Chen 	dev_for_each_subnode(node, dev) {
51*68ed8338SJoseph Chen 		key[i].name = ofnode_read_string(node, "label");
52*68ed8338SJoseph Chen 		key[i].vref = vref;
53*68ed8338SJoseph Chen 		key[i].margin = ADC_MARGIN;
54*68ed8338SJoseph Chen 		key[i].channel = adc_channels[1];
55*68ed8338SJoseph Chen 		if (ofnode_read_u32(node, "linux,code", &key[i].code)) {
56*68ed8338SJoseph Chen 			printf("%s: failed to read 'linux,code', ret=%d\n",
57*68ed8338SJoseph Chen 			       key[i].name, key[i].code);
58*68ed8338SJoseph Chen 			return -EINVAL;
59*68ed8338SJoseph Chen 		}
60*68ed8338SJoseph Chen 		if (ofnode_read_u32(node, "press-threshold-microvolt",
61*68ed8338SJoseph Chen 				    &microvolt)) {
62*68ed8338SJoseph Chen 			printf("%s: failed read 'press-threshold-microvolt', ret=%d\n",
63*68ed8338SJoseph Chen 			       key[i].name, microvolt);
64*68ed8338SJoseph Chen 			return -EINVAL;
65*68ed8338SJoseph Chen 		}
66*68ed8338SJoseph Chen 		/* Convert microvolt to adc value */
67*68ed8338SJoseph Chen 		key[i].value = microvolt / (key[i].vref / 1024);
68*68ed8338SJoseph Chen 
69*68ed8338SJoseph Chen 		debug("%s: name=%s: code=%d, vref=%d, margin=%d, channel=%d, val=%d\n",
70*68ed8338SJoseph Chen 		      __func__, key[i].name, key[i].code, key[i].vref,
71*68ed8338SJoseph Chen 		      key[i].margin, key[i].channel, key[i].value);
72*68ed8338SJoseph Chen 
73*68ed8338SJoseph Chen 		/* Next node */
74*68ed8338SJoseph Chen 		i++;
75*68ed8338SJoseph Chen 		priv->key_nr = i;
76*68ed8338SJoseph Chen 		if (i >= MAX_KEY_NR) {
77*68ed8338SJoseph Chen 			printf("Too many keys, Max support: %d\n", MAX_KEY_NR);
78*68ed8338SJoseph Chen 			return -EINVAL;
79*68ed8338SJoseph Chen 		}
80*68ed8338SJoseph Chen 	}
81*68ed8338SJoseph Chen 
82*68ed8338SJoseph Chen 	return 0;
83*68ed8338SJoseph Chen }
84*68ed8338SJoseph Chen 
85*68ed8338SJoseph Chen static int adc_keys_read(struct udevice *dev, int code)
86*68ed8338SJoseph Chen {
87*68ed8338SJoseph Chen 	struct adc_key_priv *priv = dev_get_priv(dev);
88*68ed8338SJoseph Chen 	struct input_key *key = dev_get_platdata(dev);
89*68ed8338SJoseph Chen 	int report = KEY_NOT_EXIST;
90*68ed8338SJoseph Chen 	int max, min, i = 0;
91*68ed8338SJoseph Chen 	unsigned int adcval;
92*68ed8338SJoseph Chen 
93*68ed8338SJoseph Chen 	for (i = 0; i < priv->key_nr; i++) {
94*68ed8338SJoseph Chen 		if (key[i].code != code)
95*68ed8338SJoseph Chen 			continue;
96*68ed8338SJoseph Chen 
97*68ed8338SJoseph Chen 		if (adc_channel_single_shot("saradc",
98*68ed8338SJoseph Chen 					    key[i].channel, &adcval)) {
99*68ed8338SJoseph Chen 			printf("%s: failed to read saradc\n", key[i].name);
100*68ed8338SJoseph Chen 		} else {
101*68ed8338SJoseph Chen 			/* Get min, max */
102*68ed8338SJoseph Chen 			max = key[i].value + key[i].margin;
103*68ed8338SJoseph Chen 			if (key[i].value > key[i].margin)
104*68ed8338SJoseph Chen 				min = key[i].value - key[i].margin;
105*68ed8338SJoseph Chen 			else
106*68ed8338SJoseph Chen 				min = key[i].value;
107*68ed8338SJoseph Chen 
108*68ed8338SJoseph Chen 			/* Check */
109*68ed8338SJoseph Chen 			if ((adcval <= max) && (adcval >= min)) {
110*68ed8338SJoseph Chen 				report = KEY_PRESS_DOWN;
111*68ed8338SJoseph Chen 				printf("'%s' key pressed down\n",
112*68ed8338SJoseph Chen 				       key[i].name);
113*68ed8338SJoseph Chen 			} else {
114*68ed8338SJoseph Chen 				report = KEY_PRESS_NONE;
115*68ed8338SJoseph Chen 			}
116*68ed8338SJoseph Chen 		}
117*68ed8338SJoseph Chen 		break;
118*68ed8338SJoseph Chen 	}
119*68ed8338SJoseph Chen 
120*68ed8338SJoseph Chen 	return report;
121*68ed8338SJoseph Chen }
122*68ed8338SJoseph Chen 
123*68ed8338SJoseph Chen static const struct dm_key_ops key_ops = {
124*68ed8338SJoseph Chen 	.name = "adc_keys",
125*68ed8338SJoseph Chen 	.read = adc_keys_read,
126*68ed8338SJoseph Chen };
127*68ed8338SJoseph Chen 
128*68ed8338SJoseph Chen static const struct udevice_id adc_keys_ids[] = {
129*68ed8338SJoseph Chen 	{ .compatible = "adc-keys" },
130*68ed8338SJoseph Chen 	{ },
131*68ed8338SJoseph Chen };
132*68ed8338SJoseph Chen 
133*68ed8338SJoseph Chen U_BOOT_DRIVER(adc_keys) = {
134*68ed8338SJoseph Chen 	.name   = "adc-keys",
135*68ed8338SJoseph Chen 	.id     = UCLASS_KEY,
136*68ed8338SJoseph Chen 	.ops	= &key_ops,
137*68ed8338SJoseph Chen 	.of_match = adc_keys_ids,
138*68ed8338SJoseph Chen 	.ofdata_to_platdata = adc_keys_ofdata_to_platdata,
139*68ed8338SJoseph Chen 	.platdata_auto_alloc_size = sizeof(struct input_key) * MAX_KEY_NR,
140*68ed8338SJoseph Chen 	.priv_auto_alloc_size = sizeof(struct adc_key_priv),
141*68ed8338SJoseph Chen };
142