xref: /OK3568_Linux_fs/u-boot/drivers/input/key-uclass.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2017 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 <dm.h>
11*4882a593Smuzhiyun #include <irq-generic.h>
12*4882a593Smuzhiyun #include <key.h>
13*4882a593Smuzhiyun #include <dm/lists.h>
14*4882a593Smuzhiyun #include <dm/uclass-internal.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define KEY_WARN(fmt, args...)	printf("Key Warn: "fmt, ##args)
17*4882a593Smuzhiyun #define KEY_ERR(fmt, args...)	printf("Key Error: "fmt, ##args)
18*4882a593Smuzhiyun #define KEY_DBG(fmt, args...)	 debug("Key Debug: "fmt, ##args)
19*4882a593Smuzhiyun 
arch_counter_get_cntpct(void)20*4882a593Smuzhiyun static inline uint64_t arch_counter_get_cntpct(void)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun 	uint64_t cval = 0;
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun 	isb();
25*4882a593Smuzhiyun #ifdef CONFIG_ARM64
26*4882a593Smuzhiyun 	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
27*4882a593Smuzhiyun #else
28*4882a593Smuzhiyun 	asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun 	return cval;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
key_timer(uint64_t base)33*4882a593Smuzhiyun uint64_t key_timer(uint64_t base)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	uint64_t cntpct;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	cntpct = arch_counter_get_cntpct() / 24000UL;
38*4882a593Smuzhiyun 	return (cntpct > base) ? (cntpct - base) : 0;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #ifdef CONFIG_ADC
adc_raw_to_mV(struct udevice * dev,unsigned int raw,int * mV)42*4882a593Smuzhiyun static int adc_raw_to_mV(struct udevice *dev, unsigned int raw, int *mV)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	unsigned int data_mask;
45*4882a593Smuzhiyun 	int ret, vref = 1800000;
46*4882a593Smuzhiyun 	u64 raw64 = raw;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	ret = adc_data_mask(dev, &data_mask);
49*4882a593Smuzhiyun 	if (ret)
50*4882a593Smuzhiyun 		return ret;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	raw64 *= vref;
53*4882a593Smuzhiyun 	do_div(raw64, data_mask);
54*4882a593Smuzhiyun 	*mV = raw64;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	return 0;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
key_adc_event(struct udevice * dev,struct dm_key_uclass_platdata * uc_key,int adcval)59*4882a593Smuzhiyun static int key_adc_event(struct udevice *dev,
60*4882a593Smuzhiyun 			 struct dm_key_uclass_platdata *uc_key, int adcval)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	int val = adcval;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	if (uc_key->in_volt) {
65*4882a593Smuzhiyun 		if (adc_raw_to_mV(dev, adcval, &val))
66*4882a593Smuzhiyun 			return KEY_PRESS_NONE;
67*4882a593Smuzhiyun 	}
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	debug("[%s] <%d, %d, %d>: adcval=%d -> mV=%d\n",
70*4882a593Smuzhiyun 	      uc_key->name, uc_key->min, uc_key->center, uc_key->max,
71*4882a593Smuzhiyun 	      adcval, val);
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	return (val <= uc_key->max && val >= uc_key->min) ?
74*4882a593Smuzhiyun 		KEY_PRESS_DOWN : KEY_PRESS_NONE;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun #endif
77*4882a593Smuzhiyun 
key_gpio_event(struct dm_key_uclass_platdata * uc_key)78*4882a593Smuzhiyun static int key_gpio_event(struct dm_key_uclass_platdata *uc_key)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	if (!dm_gpio_is_valid(&uc_key->gpio)) {
81*4882a593Smuzhiyun 		KEY_ERR("'%s' Invalid gpio\n", uc_key->name);
82*4882a593Smuzhiyun 		return KEY_PRESS_NONE;
83*4882a593Smuzhiyun 	}
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	return dm_gpio_get_value(&uc_key->gpio) ?
86*4882a593Smuzhiyun 	       KEY_PRESS_DOWN : KEY_PRESS_NONE;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
key_gpio_interrupt_event(struct dm_key_uclass_platdata * uc_key)89*4882a593Smuzhiyun static int key_gpio_interrupt_event(struct dm_key_uclass_platdata *uc_key)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	int event;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	debug("%s: %s: up=%llu, down=%llu, delta=%llu\n",
94*4882a593Smuzhiyun 	      __func__, uc_key->name, uc_key->rise_ms, uc_key->fall_ms,
95*4882a593Smuzhiyun 	      uc_key->rise_ms - uc_key->fall_ms);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	/* Possible this is machine power-on long pressed, so ignore this */
98*4882a593Smuzhiyun 	if (uc_key->fall_ms == 0 && uc_key->rise_ms != 0) {
99*4882a593Smuzhiyun 		event = KEY_PRESS_NONE;
100*4882a593Smuzhiyun 		goto out;
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	if ((uc_key->rise_ms > uc_key->fall_ms) &&
104*4882a593Smuzhiyun 	    (uc_key->rise_ms - uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
105*4882a593Smuzhiyun 		uc_key->rise_ms = 0;
106*4882a593Smuzhiyun 		uc_key->fall_ms = 0;
107*4882a593Smuzhiyun 		event = KEY_PRESS_LONG_DOWN;
108*4882a593Smuzhiyun 		KEY_DBG("%s key long pressed..\n", uc_key->name);
109*4882a593Smuzhiyun 	} else if (uc_key->fall_ms &&
110*4882a593Smuzhiyun 		   key_timer(uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
111*4882a593Smuzhiyun 		uc_key->rise_ms = 0;
112*4882a593Smuzhiyun 		uc_key->fall_ms = 0;
113*4882a593Smuzhiyun 		event = KEY_PRESS_LONG_DOWN;
114*4882a593Smuzhiyun 		KEY_DBG("%s key long pressed(hold)..\n", uc_key->name);
115*4882a593Smuzhiyun 	} else if ((uc_key->rise_ms > uc_key->fall_ms) &&
116*4882a593Smuzhiyun 		   (uc_key->rise_ms - uc_key->fall_ms) < KEY_LONG_DOWN_MS) {
117*4882a593Smuzhiyun 		uc_key->rise_ms = 0;
118*4882a593Smuzhiyun 		uc_key->fall_ms = 0;
119*4882a593Smuzhiyun 		event = KEY_PRESS_DOWN;
120*4882a593Smuzhiyun 		KEY_DBG("%s key short pressed..\n", uc_key->name);
121*4882a593Smuzhiyun 	/* Possible in charge animation, we enable irq after fuel gauge updated */
122*4882a593Smuzhiyun 	} else if (uc_key->rise_ms && uc_key->fall_ms &&
123*4882a593Smuzhiyun 		   (uc_key->rise_ms == uc_key->fall_ms)) {
124*4882a593Smuzhiyun 		uc_key->rise_ms = 0;
125*4882a593Smuzhiyun 		uc_key->fall_ms = 0;
126*4882a593Smuzhiyun 		event = KEY_PRESS_DOWN;
127*4882a593Smuzhiyun 		KEY_DBG("%s key short pressed..\n", uc_key->name);
128*4882a593Smuzhiyun 	} else {
129*4882a593Smuzhiyun 		event = KEY_PRESS_NONE;
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun out:
133*4882a593Smuzhiyun 	return event;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
key_is_pressed(int event)136*4882a593Smuzhiyun int key_is_pressed(int event)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	return (event == KEY_PRESS_DOWN || event == KEY_PRESS_LONG_DOWN);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
key_core_read(struct dm_key_uclass_platdata * uc_key)141*4882a593Smuzhiyun static int key_core_read(struct dm_key_uclass_platdata *uc_key)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	if (uc_key->type == ADC_KEY) {
144*4882a593Smuzhiyun #ifdef CONFIG_ADC
145*4882a593Smuzhiyun 		struct udevice *dev;
146*4882a593Smuzhiyun 		unsigned int adcval;
147*4882a593Smuzhiyun 		int ret;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 		ret = uclass_get_device_by_name(UCLASS_ADC, "saradc", &dev);
150*4882a593Smuzhiyun 		if (ret) {
151*4882a593Smuzhiyun 			KEY_ERR("%s: No saradc\n", uc_key->name);
152*4882a593Smuzhiyun 			return KEY_NOT_EXIST;
153*4882a593Smuzhiyun 		}
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		ret = adc_start_channel(dev, uc_key->channel);
156*4882a593Smuzhiyun 		if (ret) {
157*4882a593Smuzhiyun 			KEY_ERR("%s: Failed to start saradc\n", uc_key->name);
158*4882a593Smuzhiyun 			return KEY_NOT_EXIST;
159*4882a593Smuzhiyun 		}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 		ret = adc_channel_data(dev, uc_key->channel, &adcval);
162*4882a593Smuzhiyun 		if (ret) {
163*4882a593Smuzhiyun 			KEY_ERR("%s: Failed to read saradc, %d\n", uc_key->name, ret);
164*4882a593Smuzhiyun 			return KEY_NOT_EXIST;
165*4882a593Smuzhiyun 		}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 		return key_adc_event(dev, uc_key, adcval);
168*4882a593Smuzhiyun #else
169*4882a593Smuzhiyun 		return KEY_NOT_EXIST;
170*4882a593Smuzhiyun #endif
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	return (uc_key->code == KEY_POWER) ?
174*4882a593Smuzhiyun 		key_gpio_interrupt_event(uc_key) :
175*4882a593Smuzhiyun 		key_gpio_event(uc_key);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
key_read(int code)178*4882a593Smuzhiyun int key_read(int code)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	struct dm_key_uclass_platdata *uc_key;
181*4882a593Smuzhiyun 	struct udevice *dev;
182*4882a593Smuzhiyun 	struct uclass *uc;
183*4882a593Smuzhiyun 	bool allow_pre_reloc = false;
184*4882a593Smuzhiyun 	int ret, event = KEY_NOT_EXIST;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_KEY, &uc);
187*4882a593Smuzhiyun 	if (ret)
188*4882a593Smuzhiyun 		return ret;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun try_again:
191*4882a593Smuzhiyun 	for (uclass_first_device(UCLASS_KEY, &dev);
192*4882a593Smuzhiyun 	     dev;
193*4882a593Smuzhiyun 	     uclass_next_device(&dev)) {
194*4882a593Smuzhiyun 		uc_key = dev_get_uclass_platdata(dev);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 		if (!allow_pre_reloc && uc_key->pre_reloc)
197*4882a593Smuzhiyun 			continue;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 		if (uc_key->code != code)
200*4882a593Smuzhiyun 			continue;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 		event = key_core_read(uc_key);
203*4882a593Smuzhiyun 		if (key_is_pressed(event))
204*4882a593Smuzhiyun 			return event;
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	/* If not find valid key node from kernel, try from u-boot */
208*4882a593Smuzhiyun 	if (event == KEY_NOT_EXIST && !allow_pre_reloc) {
209*4882a593Smuzhiyun 		allow_pre_reloc = true;
210*4882a593Smuzhiyun 		goto try_again;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return event;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
key_exist(int code)216*4882a593Smuzhiyun int key_exist(int code)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	struct dm_key_uclass_platdata *uc_key;
219*4882a593Smuzhiyun 	struct udevice *dev;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	for (uclass_find_first_device(UCLASS_KEY, &dev);
222*4882a593Smuzhiyun 	     dev;
223*4882a593Smuzhiyun 	     uclass_find_next_device(&dev)) {
224*4882a593Smuzhiyun 		uc_key = dev_get_uclass_platdata(dev);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 		if (uc_key->code == code)
227*4882a593Smuzhiyun 			return 1;
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	return 0;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(IRQ)
234*4882a593Smuzhiyun #if defined(CONFIG_PWRKEY_DNL_TRIGGER_NUM) && \
235*4882a593Smuzhiyun 		(CONFIG_PWRKEY_DNL_TRIGGER_NUM > 0)
power_key_download(struct dm_key_uclass_platdata * uc_key)236*4882a593Smuzhiyun static void power_key_download(struct dm_key_uclass_platdata *uc_key)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun 	int trig_cnt = CONFIG_PWRKEY_DNL_TRIGGER_NUM;
239*4882a593Smuzhiyun 	static u64 old_rise_ms;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	if (uc_key->code == KEY_POWER && old_rise_ms != uc_key->rise_ms) {
242*4882a593Smuzhiyun 		old_rise_ms = uc_key->rise_ms;
243*4882a593Smuzhiyun 		uc_key->trig_cnt++;
244*4882a593Smuzhiyun 		if (uc_key->trig_cnt >= trig_cnt) {
245*4882a593Smuzhiyun 			printf("\nEnter download mode by pwrkey\n");
246*4882a593Smuzhiyun 			irq_handler_disable(uc_key->irq);
247*4882a593Smuzhiyun 			run_command("download", 0);
248*4882a593Smuzhiyun 		}
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
pwrkey_download_init(void)252*4882a593Smuzhiyun int pwrkey_download_init(void)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	return (KEY_NOT_EXIST == key_read(KEY_POWER));
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun #endif
257*4882a593Smuzhiyun 
gpio_irq_handler(int irq,void * data)258*4882a593Smuzhiyun static void gpio_irq_handler(int irq, void *data)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 	struct udevice *dev = data;
261*4882a593Smuzhiyun 	struct dm_key_uclass_platdata *uc_key = dev_get_uclass_platdata(dev);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (uc_key->irq != irq)
264*4882a593Smuzhiyun 		return;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	if (uc_key->irq_thread) {
267*4882a593Smuzhiyun 		uc_key->irq_thread(irq, data);
268*4882a593Smuzhiyun 	} else {
269*4882a593Smuzhiyun 		if (irq_get_gpio_level(irq)) {
270*4882a593Smuzhiyun 			uc_key->rise_ms = key_timer(0);
271*4882a593Smuzhiyun 			KEY_DBG("%s: key dn: %llu ms\n",
272*4882a593Smuzhiyun 				uc_key->name, uc_key->fall_ms);
273*4882a593Smuzhiyun 		} else {
274*4882a593Smuzhiyun 			uc_key->fall_ms = key_timer(0);
275*4882a593Smuzhiyun 			KEY_DBG("%s: key up: %llu ms\n",
276*4882a593Smuzhiyun 				uc_key->name, uc_key->rise_ms);
277*4882a593Smuzhiyun 		}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 		/* Must delay */
280*4882a593Smuzhiyun 		mdelay(10);
281*4882a593Smuzhiyun 		irq_revert_irq_type(irq);
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/* Hook event: enter download mode by pwrkey */
285*4882a593Smuzhiyun #if defined(CONFIG_PWRKEY_DNL_TRIGGER_NUM) && \
286*4882a593Smuzhiyun 		(CONFIG_PWRKEY_DNL_TRIGGER_NUM > 0)
287*4882a593Smuzhiyun 	power_key_download(uc_key);
288*4882a593Smuzhiyun #endif
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun #endif
291*4882a593Smuzhiyun 
key_bind_children(struct udevice * dev,const char * drv_name)292*4882a593Smuzhiyun int key_bind_children(struct udevice *dev, const char *drv_name)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	const char *name;
295*4882a593Smuzhiyun 	ofnode node;
296*4882a593Smuzhiyun 	int ret;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	dev_for_each_subnode(node, dev) {
299*4882a593Smuzhiyun 		/*
300*4882a593Smuzhiyun 		 * If this node has "compatible" property, this is not
301*4882a593Smuzhiyun 		 * a amp subnode, but a normal device. skip.
302*4882a593Smuzhiyun 		 */
303*4882a593Smuzhiyun 		ofnode_get_property(node, "compatible", &ret);
304*4882a593Smuzhiyun 		if (ret >= 0)
305*4882a593Smuzhiyun 			continue;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 		if (ret != -FDT_ERR_NOTFOUND)
308*4882a593Smuzhiyun 			return ret;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 		name = ofnode_get_name(node);
311*4882a593Smuzhiyun 		if (!name)
312*4882a593Smuzhiyun 			return -EINVAL;
313*4882a593Smuzhiyun 		ret = device_bind_driver_to_node(dev, drv_name, name,
314*4882a593Smuzhiyun 						 node, NULL);
315*4882a593Smuzhiyun 		if (ret)
316*4882a593Smuzhiyun 			return ret;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	return 0;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
key_post_probe(struct udevice * dev)322*4882a593Smuzhiyun static int key_post_probe(struct udevice *dev)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	struct dm_key_uclass_platdata *uc_key;
325*4882a593Smuzhiyun 	int ret;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	uc_key = dev_get_uclass_platdata(dev);
328*4882a593Smuzhiyun 	if (!uc_key)
329*4882a593Smuzhiyun 		return -ENXIO;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	/* True from U-Boot key node */
332*4882a593Smuzhiyun 	uc_key->pre_reloc = dev_read_bool(dev, "u-boot,dm-pre-reloc") ||
333*4882a593Smuzhiyun 			    dev_read_bool(dev, "u-boot,dm-spl");
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (uc_key->type != ADC_KEY) {
336*4882a593Smuzhiyun 		if (uc_key->code == KEY_POWER) {
337*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(IRQ)
338*4882a593Smuzhiyun 			int irq;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 			if (uc_key->skip_irq_init)
341*4882a593Smuzhiyun 				return 0;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 			irq = phandle_gpio_to_irq(uc_key->gpios[0],
344*4882a593Smuzhiyun 						  uc_key->gpios[1]);
345*4882a593Smuzhiyun 			if (irq < 0) {
346*4882a593Smuzhiyun 				KEY_ERR("%s: failed to request irq, ret=%d\n",
347*4882a593Smuzhiyun 					uc_key->name, irq);
348*4882a593Smuzhiyun 				return irq;
349*4882a593Smuzhiyun 			}
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 			if (uc_key->code != KEY_POWER && uc_key->irq_thread) {
352*4882a593Smuzhiyun 				KEY_WARN("%s: only power key can request irq thread\n",
353*4882a593Smuzhiyun 					 uc_key->name);
354*4882a593Smuzhiyun 				return -EINVAL;
355*4882a593Smuzhiyun 			}
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 			uc_key->irq = irq;
358*4882a593Smuzhiyun 			irq_install_handler(irq, gpio_irq_handler, dev);
359*4882a593Smuzhiyun 			irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
360*4882a593Smuzhiyun 			irq_handler_enable(irq);
361*4882a593Smuzhiyun #else
362*4882a593Smuzhiyun 			KEY_WARN("%s: no IRQ framework available\n", uc_key->name);
363*4882a593Smuzhiyun #endif
364*4882a593Smuzhiyun 		} else {
365*4882a593Smuzhiyun 			ret = gpio_request_by_name(dev, "gpios", 0,
366*4882a593Smuzhiyun 						   &uc_key->gpio, GPIOD_IS_IN);
367*4882a593Smuzhiyun 			if (ret) {
368*4882a593Smuzhiyun 				KEY_ERR("%s: failed to request gpio, ret=%d\n",
369*4882a593Smuzhiyun 					uc_key->name, ret);
370*4882a593Smuzhiyun 				return ret;
371*4882a593Smuzhiyun 			}
372*4882a593Smuzhiyun 		}
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun #ifdef DEBUG
376*4882a593Smuzhiyun 	printf("[%s] (%s, %s, %s):\n", uc_key->name,
377*4882a593Smuzhiyun 	       uc_key->type == ADC_KEY ? "ADC" : "GPIO",
378*4882a593Smuzhiyun 	       uc_key->pre_reloc ? "U-Boot" : "Kernel",
379*4882a593Smuzhiyun 	       dev->parent->name);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	if (uc_key->type == ADC_KEY) {
382*4882a593Smuzhiyun 		printf("      %s: %d (%d, %d)\n",
383*4882a593Smuzhiyun 		       uc_key->in_volt ? "volt" : " adc",
384*4882a593Smuzhiyun 		       uc_key->center, uc_key->min, uc_key->max);
385*4882a593Smuzhiyun 		printf("   channel: %d\n\n", uc_key->channel);
386*4882a593Smuzhiyun 	} else {
387*4882a593Smuzhiyun 		const char *gpio_name =
388*4882a593Smuzhiyun 		     ofnode_get_name(ofnode_get_by_phandle(uc_key->gpios[0]));
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 		printf("       irq: %d\n", uc_key->irq);
391*4882a593Smuzhiyun 		printf("   gpio[0]: %s\n", gpio_name);
392*4882a593Smuzhiyun 		printf("   gpio[1]: %d\n\n", uc_key->gpios[1]);
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun #endif
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	return 0;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun UCLASS_DRIVER(key) = {
400*4882a593Smuzhiyun 	.id		= UCLASS_KEY,
401*4882a593Smuzhiyun 	.name		= "key",
402*4882a593Smuzhiyun 	.post_probe	= key_post_probe,
403*4882a593Smuzhiyun 	.per_device_platdata_auto_alloc_size =
404*4882a593Smuzhiyun 			sizeof(struct dm_key_uclass_platdata),
405*4882a593Smuzhiyun };
406