xref: /rk3399_rockchip-uboot/drivers/input/key-uclass.c (revision 9b0d00c59646f2ef15723ac8b3e0ba6c16992eca)
1b398a9a7SJoseph Chen /*
2b398a9a7SJoseph Chen  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3b398a9a7SJoseph Chen  *
4b398a9a7SJoseph Chen  * SPDX-License-Identifier:     GPL-2.0+
5b398a9a7SJoseph Chen  */
6b398a9a7SJoseph Chen 
764048c53SJoseph Chen #include <common.h>
864048c53SJoseph Chen #include <adc.h>
915da1b50SJoseph Chen #include <div64.h>
10b398a9a7SJoseph Chen #include <dm.h>
1118fdcbceSJoseph Chen #include <irq-generic.h>
12b398a9a7SJoseph Chen #include <key.h>
135a54baa7SJoseph Chen #include <dm/lists.h>
1418fdcbceSJoseph Chen #include <dm/uclass-internal.h>
1564048c53SJoseph Chen 
165a54baa7SJoseph Chen #define KEY_WARN(fmt, args...)	printf("Key Warn: "fmt, ##args)
175a54baa7SJoseph Chen #define KEY_ERR(fmt, args...)	printf("Key Error: "fmt, ##args)
185a54baa7SJoseph Chen #define KEY_DBG(fmt, args...)	 debug("Key Debug: "fmt, ##args)
19adba3792SJoseph Chen 
20a2df9606SJoseph Chen static inline uint64_t arch_counter_get_cntpct(void)
21a2df9606SJoseph Chen {
22a2df9606SJoseph Chen 	uint64_t cval = 0;
23a2df9606SJoseph Chen 
24a2df9606SJoseph Chen 	isb();
25a2df9606SJoseph Chen #ifdef CONFIG_ARM64
26a2df9606SJoseph Chen 	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
27a2df9606SJoseph Chen #else
28a2df9606SJoseph Chen 	asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
29a2df9606SJoseph Chen #endif
30a2df9606SJoseph Chen 	return cval;
31a2df9606SJoseph Chen }
32a2df9606SJoseph Chen 
3364048c53SJoseph Chen uint64_t key_timer(uint64_t base)
34a2df9606SJoseph Chen {
35a2df9606SJoseph Chen 	uint64_t cntpct;
36a2df9606SJoseph Chen 
37a2df9606SJoseph Chen 	cntpct = arch_counter_get_cntpct() / 24000UL;
38a2df9606SJoseph Chen 	return (cntpct > base) ? (cntpct - base) : 0;
39a2df9606SJoseph Chen }
40a2df9606SJoseph Chen 
41eb104afcSJoseph Chen #ifdef CONFIG_ADC
42*9b0d00c5SJoseph Chen static int adc_raw_to_mV(struct udevice *dev, unsigned int raw, int *mV)
43a2df9606SJoseph Chen {
4415da1b50SJoseph Chen 	unsigned int data_mask;
4515da1b50SJoseph Chen 	int ret, vref = 1800000;
4615da1b50SJoseph Chen 	u64 raw64 = raw;
4715da1b50SJoseph Chen 
4815da1b50SJoseph Chen 	ret = adc_data_mask(dev, &data_mask);
4915da1b50SJoseph Chen 	if (ret)
5015da1b50SJoseph Chen 		return ret;
5115da1b50SJoseph Chen 
5215da1b50SJoseph Chen 	raw64 *= vref;
5315da1b50SJoseph Chen 	do_div(raw64, data_mask);
54*9b0d00c5SJoseph Chen 	*mV = raw64;
5515da1b50SJoseph Chen 
5615da1b50SJoseph Chen 	return 0;
5715da1b50SJoseph Chen }
5815da1b50SJoseph Chen 
5915da1b50SJoseph Chen static int key_adc_event(struct udevice *dev,
6015da1b50SJoseph Chen 			 struct dm_key_uclass_platdata *uc_key, int adcval)
6115da1b50SJoseph Chen {
6215da1b50SJoseph Chen 	int val = adcval;
6315da1b50SJoseph Chen 
6415da1b50SJoseph Chen 	if (uc_key->in_volt) {
65*9b0d00c5SJoseph Chen 		if (adc_raw_to_mV(dev, adcval, &val))
6615da1b50SJoseph Chen 			return KEY_PRESS_NONE;
6715da1b50SJoseph Chen 	}
6815da1b50SJoseph Chen 
69*9b0d00c5SJoseph Chen 	debug("[%s] <%d, %d, %d>: adcval=%d -> mV=%d\n",
7015da1b50SJoseph Chen 	      uc_key->name, uc_key->min, uc_key->center, uc_key->max,
7115da1b50SJoseph Chen 	      adcval, val);
7215da1b50SJoseph Chen 
7315da1b50SJoseph Chen 	return (val <= uc_key->max && val >= uc_key->min) ?
745a54baa7SJoseph Chen 		KEY_PRESS_DOWN : KEY_PRESS_NONE;
753fb84000SJoseph Chen }
76eb104afcSJoseph Chen #endif
773fb84000SJoseph Chen 
785a54baa7SJoseph Chen static int key_gpio_event(struct dm_key_uclass_platdata *uc_key)
793fb84000SJoseph Chen {
805a54baa7SJoseph Chen 	if (!dm_gpio_is_valid(&uc_key->gpio)) {
815a54baa7SJoseph Chen 		KEY_ERR("'%s' Invalid gpio\n", uc_key->name);
8264048c53SJoseph Chen 		return KEY_PRESS_NONE;
8364048c53SJoseph Chen 	}
8464048c53SJoseph Chen 
855a54baa7SJoseph Chen 	return dm_gpio_get_value(&uc_key->gpio) ?
865a54baa7SJoseph Chen 	       KEY_PRESS_DOWN : KEY_PRESS_NONE;
8764048c53SJoseph Chen }
8864048c53SJoseph Chen 
895a54baa7SJoseph Chen static int key_gpio_interrupt_event(struct dm_key_uclass_platdata *uc_key)
9064048c53SJoseph Chen {
915a54baa7SJoseph Chen 	int event;
923fb84000SJoseph Chen 
933fb84000SJoseph Chen 	debug("%s: %s: up=%llu, down=%llu, delta=%llu\n",
945a54baa7SJoseph Chen 	      __func__, uc_key->name, uc_key->rise_ms, uc_key->fall_ms,
955a54baa7SJoseph Chen 	      uc_key->rise_ms - uc_key->fall_ms);
963fb84000SJoseph Chen 
973fb84000SJoseph Chen 	/* Possible this is machine power-on long pressed, so ignore this */
985a54baa7SJoseph Chen 	if (uc_key->fall_ms == 0 && uc_key->rise_ms != 0) {
995a54baa7SJoseph Chen 		event = KEY_PRESS_NONE;
1003fb84000SJoseph Chen 		goto out;
1013fb84000SJoseph Chen 	}
1023fb84000SJoseph Chen 
1035a54baa7SJoseph Chen 	if ((uc_key->rise_ms > uc_key->fall_ms) &&
1045a54baa7SJoseph Chen 	    (uc_key->rise_ms - uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
1055a54baa7SJoseph Chen 		uc_key->rise_ms = 0;
1065a54baa7SJoseph Chen 		uc_key->fall_ms = 0;
1075a54baa7SJoseph Chen 		event = KEY_PRESS_LONG_DOWN;
1085a54baa7SJoseph Chen 		KEY_DBG("%s key long pressed..\n", uc_key->name);
1095a54baa7SJoseph Chen 	} else if (uc_key->fall_ms &&
1105a54baa7SJoseph Chen 		   key_timer(uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
1115a54baa7SJoseph Chen 		uc_key->rise_ms = 0;
1125a54baa7SJoseph Chen 		uc_key->fall_ms = 0;
1135a54baa7SJoseph Chen 		event = KEY_PRESS_LONG_DOWN;
1145a54baa7SJoseph Chen 		KEY_DBG("%s key long pressed(hold)..\n", uc_key->name);
1155a54baa7SJoseph Chen 	} else if ((uc_key->rise_ms > uc_key->fall_ms) &&
1165a54baa7SJoseph Chen 		   (uc_key->rise_ms - uc_key->fall_ms) < KEY_LONG_DOWN_MS) {
1175a54baa7SJoseph Chen 		uc_key->rise_ms = 0;
1185a54baa7SJoseph Chen 		uc_key->fall_ms = 0;
1195a54baa7SJoseph Chen 		event = KEY_PRESS_DOWN;
1205a54baa7SJoseph Chen 		KEY_DBG("%s key short pressed..\n", uc_key->name);
12164048c53SJoseph Chen 	/* Possible in charge animation, we enable irq after fuel gauge updated */
1225a54baa7SJoseph Chen 	} else if (uc_key->rise_ms && uc_key->fall_ms &&
1235a54baa7SJoseph Chen 		   (uc_key->rise_ms == uc_key->fall_ms)) {
1245a54baa7SJoseph Chen 		uc_key->rise_ms = 0;
1255a54baa7SJoseph Chen 		uc_key->fall_ms = 0;
1265a54baa7SJoseph Chen 		event = KEY_PRESS_DOWN;
1275a54baa7SJoseph Chen 		KEY_DBG("%s key short pressed..\n", uc_key->name);
1283fb84000SJoseph Chen 	} else {
1295a54baa7SJoseph Chen 		event = KEY_PRESS_NONE;
1303fb84000SJoseph Chen 	}
1313fb84000SJoseph Chen 
1323fb84000SJoseph Chen out:
1335a54baa7SJoseph Chen 	return event;
13464048c53SJoseph Chen }
13564048c53SJoseph Chen 
1365a54baa7SJoseph Chen int key_is_pressed(int event)
13764048c53SJoseph Chen {
1385a54baa7SJoseph Chen 	return (event == KEY_PRESS_DOWN || event == KEY_PRESS_LONG_DOWN);
13964048c53SJoseph Chen }
14064048c53SJoseph Chen 
1415a54baa7SJoseph Chen static int key_core_read(struct dm_key_uclass_platdata *uc_key)
14264048c53SJoseph Chen {
143eb104afcSJoseph Chen 	if (uc_key->type == ADC_KEY) {
144eb104afcSJoseph Chen #ifdef CONFIG_ADC
14515da1b50SJoseph Chen 		struct udevice *dev;
14664048c53SJoseph Chen 		unsigned int adcval;
14715da1b50SJoseph Chen 		int ret;
14864048c53SJoseph Chen 
14915da1b50SJoseph Chen 		ret = uclass_get_device_by_name(UCLASS_ADC, "saradc", &dev);
15015da1b50SJoseph Chen 		if (ret) {
15115da1b50SJoseph Chen 			KEY_ERR("%s: No saradc\n", uc_key->name);
1525a54baa7SJoseph Chen 			return KEY_NOT_EXIST;
15364048c53SJoseph Chen 		}
15464048c53SJoseph Chen 
15515da1b50SJoseph Chen 		ret = adc_start_channel(dev, uc_key->channel);
15615da1b50SJoseph Chen 		if (ret) {
15715da1b50SJoseph Chen 			KEY_ERR("%s: Failed to start saradc\n", uc_key->name);
15815da1b50SJoseph Chen 			return KEY_NOT_EXIST;
15915da1b50SJoseph Chen 		}
16015da1b50SJoseph Chen 
16115da1b50SJoseph Chen 		ret = adc_channel_data(dev, uc_key->channel, &adcval);
16215da1b50SJoseph Chen 		if (ret) {
16315da1b50SJoseph Chen 			KEY_ERR("%s: Failed to read saradc, %d\n", uc_key->name, ret);
16415da1b50SJoseph Chen 			return KEY_NOT_EXIST;
16515da1b50SJoseph Chen 		}
16615da1b50SJoseph Chen 
16715da1b50SJoseph Chen 		return key_adc_event(dev, uc_key, adcval);
168eb104afcSJoseph Chen #else
169eb104afcSJoseph Chen 		return KEY_NOT_EXIST;
170eb104afcSJoseph Chen #endif
1715a54baa7SJoseph Chen 	}
17264048c53SJoseph Chen 
1735a54baa7SJoseph Chen 	return (uc_key->code == KEY_POWER) ?
1745a54baa7SJoseph Chen 		key_gpio_interrupt_event(uc_key) :
1755a54baa7SJoseph Chen 		key_gpio_event(uc_key);
1769f1dd9dfSJoseph Chen }
1779f1dd9dfSJoseph Chen 
1789f1dd9dfSJoseph Chen int key_read(int code)
1799f1dd9dfSJoseph Chen {
1805a54baa7SJoseph Chen 	struct dm_key_uclass_platdata *uc_key;
1819f1dd9dfSJoseph Chen 	struct udevice *dev;
1825a54baa7SJoseph Chen 	struct uclass *uc;
1835a54baa7SJoseph Chen 	bool allow_pre_reloc = false;
1845a54baa7SJoseph Chen 	int ret, event = KEY_NOT_EXIST;
1859f1dd9dfSJoseph Chen 
1865a54baa7SJoseph Chen 	ret = uclass_get(UCLASS_KEY, &uc);
1875a54baa7SJoseph Chen 	if (ret)
1885a54baa7SJoseph Chen 		return ret;
1895a54baa7SJoseph Chen 
1905a54baa7SJoseph Chen try_again:
1919f1dd9dfSJoseph Chen 	for (uclass_first_device(UCLASS_KEY, &dev);
1929f1dd9dfSJoseph Chen 	     dev;
1939f1dd9dfSJoseph Chen 	     uclass_next_device(&dev)) {
1945a54baa7SJoseph Chen 		uc_key = dev_get_uclass_platdata(dev);
1959f1dd9dfSJoseph Chen 
1965a54baa7SJoseph Chen 		if (!allow_pre_reloc && uc_key->pre_reloc)
1979f1dd9dfSJoseph Chen 			continue;
1989f1dd9dfSJoseph Chen 
1995a54baa7SJoseph Chen 		if (uc_key->code != code)
2009f1dd9dfSJoseph Chen 			continue;
2019f1dd9dfSJoseph Chen 
2025a54baa7SJoseph Chen 		event = key_core_read(uc_key);
2035a54baa7SJoseph Chen 		if (key_is_pressed(event))
2045a54baa7SJoseph Chen 			return event;
2055a54baa7SJoseph Chen 	}
2065a54baa7SJoseph Chen 
2075a54baa7SJoseph Chen 	/* If not find valid key node from kernel, try from u-boot */
2085a54baa7SJoseph Chen 	if (event == KEY_NOT_EXIST && !allow_pre_reloc) {
2095a54baa7SJoseph Chen 		allow_pre_reloc = true;
2105a54baa7SJoseph Chen 		goto try_again;
2115a54baa7SJoseph Chen 	}
2125a54baa7SJoseph Chen 
2135a54baa7SJoseph Chen 	return event;
2145a54baa7SJoseph Chen }
2155a54baa7SJoseph Chen 
21618fdcbceSJoseph Chen int key_exist(int code)
21718fdcbceSJoseph Chen {
21818fdcbceSJoseph Chen 	struct dm_key_uclass_platdata *uc_key;
21918fdcbceSJoseph Chen 	struct udevice *dev;
22018fdcbceSJoseph Chen 
22118fdcbceSJoseph Chen 	for (uclass_find_first_device(UCLASS_KEY, &dev);
22218fdcbceSJoseph Chen 	     dev;
22318fdcbceSJoseph Chen 	     uclass_find_next_device(&dev)) {
22418fdcbceSJoseph Chen 		uc_key = dev_get_uclass_platdata(dev);
22518fdcbceSJoseph Chen 
22618fdcbceSJoseph Chen 		if (uc_key->code == code)
22718fdcbceSJoseph Chen 			return 1;
22818fdcbceSJoseph Chen 	}
22918fdcbceSJoseph Chen 
23018fdcbceSJoseph Chen 	return 0;
23118fdcbceSJoseph Chen }
23218fdcbceSJoseph Chen 
2337cef7918SJoseph Chen #if CONFIG_IS_ENABLED(IRQ)
2341a9c8b1bSJoseph Chen #if defined(CONFIG_PWRKEY_DNL_TRIGGER_NUM) && \
2351a9c8b1bSJoseph Chen 		(CONFIG_PWRKEY_DNL_TRIGGER_NUM > 0)
2361a9c8b1bSJoseph Chen static void power_key_download(struct dm_key_uclass_platdata *uc_key)
2371a9c8b1bSJoseph Chen {
2381a9c8b1bSJoseph Chen 	int trig_cnt = CONFIG_PWRKEY_DNL_TRIGGER_NUM;
2391a9c8b1bSJoseph Chen 	static u64 old_rise_ms;
2401a9c8b1bSJoseph Chen 
2411a9c8b1bSJoseph Chen 	if (uc_key->code == KEY_POWER && old_rise_ms != uc_key->rise_ms) {
2421a9c8b1bSJoseph Chen 		old_rise_ms = uc_key->rise_ms;
2431a9c8b1bSJoseph Chen 		uc_key->trig_cnt++;
2441a9c8b1bSJoseph Chen 		if (uc_key->trig_cnt >= trig_cnt) {
2451a9c8b1bSJoseph Chen 			printf("\nEnter download mode by pwrkey\n");
2461a9c8b1bSJoseph Chen 			irq_handler_disable(uc_key->irq);
247b40ac3b4SJoseph Chen 			run_command("download", 0);
2481a9c8b1bSJoseph Chen 		}
2491a9c8b1bSJoseph Chen 	}
2501a9c8b1bSJoseph Chen }
2511a9c8b1bSJoseph Chen 
2521a9c8b1bSJoseph Chen int pwrkey_download_init(void)
2531a9c8b1bSJoseph Chen {
2541a9c8b1bSJoseph Chen 	return (KEY_NOT_EXIST == key_read(KEY_POWER));
2551a9c8b1bSJoseph Chen }
2561a9c8b1bSJoseph Chen #endif
2571a9c8b1bSJoseph Chen 
2585a54baa7SJoseph Chen static void gpio_irq_handler(int irq, void *data)
2595a54baa7SJoseph Chen {
260c2e7a0d4SJoseph Chen 	struct udevice *dev = data;
261c2e7a0d4SJoseph Chen 	struct dm_key_uclass_platdata *uc_key = dev_get_uclass_platdata(dev);
2625a54baa7SJoseph Chen 
2635a54baa7SJoseph Chen 	if (uc_key->irq != irq)
2645a54baa7SJoseph Chen 		return;
2655a54baa7SJoseph Chen 
266c2e7a0d4SJoseph Chen 	if (uc_key->irq_thread) {
267c2e7a0d4SJoseph Chen 		uc_key->irq_thread(irq, data);
268c2e7a0d4SJoseph Chen 	} else {
2695a54baa7SJoseph Chen 		if (irq_get_gpio_level(irq)) {
2705a54baa7SJoseph Chen 			uc_key->rise_ms = key_timer(0);
271c2e7a0d4SJoseph Chen 			KEY_DBG("%s: key dn: %llu ms\n",
272c2e7a0d4SJoseph Chen 				uc_key->name, uc_key->fall_ms);
2735a54baa7SJoseph Chen 		} else {
2745a54baa7SJoseph Chen 			uc_key->fall_ms = key_timer(0);
275c2e7a0d4SJoseph Chen 			KEY_DBG("%s: key up: %llu ms\n",
276c2e7a0d4SJoseph Chen 				uc_key->name, uc_key->rise_ms);
2775a54baa7SJoseph Chen 		}
2785a54baa7SJoseph Chen 
2795a54baa7SJoseph Chen 		/* Must delay */
2805a54baa7SJoseph Chen 		mdelay(10);
2815a54baa7SJoseph Chen 		irq_revert_irq_type(irq);
2825a54baa7SJoseph Chen 	}
2831a9c8b1bSJoseph Chen 
2841a9c8b1bSJoseph Chen 	/* Hook event: enter download mode by pwrkey */
2851a9c8b1bSJoseph Chen #if defined(CONFIG_PWRKEY_DNL_TRIGGER_NUM) && \
2861a9c8b1bSJoseph Chen 		(CONFIG_PWRKEY_DNL_TRIGGER_NUM > 0)
2871a9c8b1bSJoseph Chen 	power_key_download(uc_key);
2881a9c8b1bSJoseph Chen #endif
289c2e7a0d4SJoseph Chen }
2905a54baa7SJoseph Chen #endif
2915a54baa7SJoseph Chen 
2925a54baa7SJoseph Chen int key_bind_children(struct udevice *dev, const char *drv_name)
2935a54baa7SJoseph Chen {
2945a54baa7SJoseph Chen 	const char *name;
2955a54baa7SJoseph Chen 	ofnode node;
2965a54baa7SJoseph Chen 	int ret;
2975a54baa7SJoseph Chen 
2985a54baa7SJoseph Chen 	dev_for_each_subnode(node, dev) {
2995a54baa7SJoseph Chen 		/*
3005a54baa7SJoseph Chen 		 * If this node has "compatible" property, this is not
3015a54baa7SJoseph Chen 		 * a amp subnode, but a normal device. skip.
3025a54baa7SJoseph Chen 		 */
3035a54baa7SJoseph Chen 		ofnode_get_property(node, "compatible", &ret);
3045a54baa7SJoseph Chen 		if (ret >= 0)
3055a54baa7SJoseph Chen 			continue;
3065a54baa7SJoseph Chen 
3075a54baa7SJoseph Chen 		if (ret != -FDT_ERR_NOTFOUND)
3085a54baa7SJoseph Chen 			return ret;
3095a54baa7SJoseph Chen 
3105a54baa7SJoseph Chen 		name = ofnode_get_name(node);
3115a54baa7SJoseph Chen 		if (!name)
3125a54baa7SJoseph Chen 			return -EINVAL;
3135a54baa7SJoseph Chen 		ret = device_bind_driver_to_node(dev, drv_name, name,
3145a54baa7SJoseph Chen 						 node, NULL);
3155a54baa7SJoseph Chen 		if (ret)
3165a54baa7SJoseph Chen 			return ret;
3175a54baa7SJoseph Chen 	}
3185a54baa7SJoseph Chen 
3195a54baa7SJoseph Chen 	return 0;
3205a54baa7SJoseph Chen }
3215a54baa7SJoseph Chen 
3225a54baa7SJoseph Chen static int key_post_probe(struct udevice *dev)
3235a54baa7SJoseph Chen {
3245a54baa7SJoseph Chen 	struct dm_key_uclass_platdata *uc_key;
3255a54baa7SJoseph Chen 	int ret;
32615da1b50SJoseph Chen 
3275a54baa7SJoseph Chen 	uc_key = dev_get_uclass_platdata(dev);
3285a54baa7SJoseph Chen 	if (!uc_key)
3295a54baa7SJoseph Chen 		return -ENXIO;
3305a54baa7SJoseph Chen 
3315a54baa7SJoseph Chen 	/* True from U-Boot key node */
332930ceb12SJoseph Chen 	uc_key->pre_reloc = dev_read_bool(dev, "u-boot,dm-pre-reloc") ||
333930ceb12SJoseph Chen 			    dev_read_bool(dev, "u-boot,dm-spl");
3345a54baa7SJoseph Chen 
33515da1b50SJoseph Chen 	if (uc_key->type != ADC_KEY) {
3365a54baa7SJoseph Chen 		if (uc_key->code == KEY_POWER) {
3377cef7918SJoseph Chen #if CONFIG_IS_ENABLED(IRQ)
3385a54baa7SJoseph Chen 			int irq;
3395a54baa7SJoseph Chen 
3400f9d23eaSJoseph Chen 			if (uc_key->skip_irq_init)
3410f9d23eaSJoseph Chen 				return 0;
3420f9d23eaSJoseph Chen 
3435a54baa7SJoseph Chen 			irq = phandle_gpio_to_irq(uc_key->gpios[0],
3445a54baa7SJoseph Chen 						  uc_key->gpios[1]);
3455a54baa7SJoseph Chen 			if (irq < 0) {
3465a54baa7SJoseph Chen 				KEY_ERR("%s: failed to request irq, ret=%d\n",
3475a54baa7SJoseph Chen 					uc_key->name, irq);
3485a54baa7SJoseph Chen 				return irq;
3495a54baa7SJoseph Chen 			}
3505a54baa7SJoseph Chen 
351c2e7a0d4SJoseph Chen 			if (uc_key->code != KEY_POWER && uc_key->irq_thread) {
352c2e7a0d4SJoseph Chen 				KEY_WARN("%s: only power key can request irq thread\n",
353c2e7a0d4SJoseph Chen 					 uc_key->name);
354c2e7a0d4SJoseph Chen 				return -EINVAL;
355c2e7a0d4SJoseph Chen 			}
356c2e7a0d4SJoseph Chen 
3575a54baa7SJoseph Chen 			uc_key->irq = irq;
358c2e7a0d4SJoseph Chen 			irq_install_handler(irq, gpio_irq_handler, dev);
3595a54baa7SJoseph Chen 			irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
3605a54baa7SJoseph Chen 			irq_handler_enable(irq);
3615a54baa7SJoseph Chen #else
3625a54baa7SJoseph Chen 			KEY_WARN("%s: no IRQ framework available\n", uc_key->name);
3635a54baa7SJoseph Chen #endif
3645a54baa7SJoseph Chen 		} else {
3655a54baa7SJoseph Chen 			ret = gpio_request_by_name(dev, "gpios", 0,
3665a54baa7SJoseph Chen 						   &uc_key->gpio, GPIOD_IS_IN);
3675a54baa7SJoseph Chen 			if (ret) {
3685a54baa7SJoseph Chen 				KEY_ERR("%s: failed to request gpio, ret=%d\n",
3695a54baa7SJoseph Chen 					uc_key->name, ret);
3705a54baa7SJoseph Chen 				return ret;
3715a54baa7SJoseph Chen 			}
3729f1dd9dfSJoseph Chen 		}
373adba3792SJoseph Chen 	}
374adba3792SJoseph Chen 
3755a54baa7SJoseph Chen #ifdef DEBUG
3765a54baa7SJoseph Chen 	printf("[%s] (%s, %s, %s):\n", uc_key->name,
3775a54baa7SJoseph Chen 	       uc_key->type == ADC_KEY ? "ADC" : "GPIO",
3785a54baa7SJoseph Chen 	       uc_key->pre_reloc ? "U-Boot" : "Kernel",
3795a54baa7SJoseph Chen 	       dev->parent->name);
3805a54baa7SJoseph Chen 
3815a54baa7SJoseph Chen 	if (uc_key->type == ADC_KEY) {
38215da1b50SJoseph Chen 		printf("      %s: %d (%d, %d)\n",
38315da1b50SJoseph Chen 		       uc_key->in_volt ? "volt" : " adc",
38415da1b50SJoseph Chen 		       uc_key->center, uc_key->min, uc_key->max);
3855a54baa7SJoseph Chen 		printf("   channel: %d\n\n", uc_key->channel);
3865a54baa7SJoseph Chen 	} else {
3875a54baa7SJoseph Chen 		const char *gpio_name =
3885a54baa7SJoseph Chen 		     ofnode_get_name(ofnode_get_by_phandle(uc_key->gpios[0]));
3895a54baa7SJoseph Chen 
3905a54baa7SJoseph Chen 		printf("       irq: %d\n", uc_key->irq);
3915a54baa7SJoseph Chen 		printf("   gpio[0]: %s\n", gpio_name);
3925a54baa7SJoseph Chen 		printf("   gpio[1]: %d\n\n", uc_key->gpios[1]);
3935a54baa7SJoseph Chen 	}
3945a54baa7SJoseph Chen #endif
3955a54baa7SJoseph Chen 
3965a54baa7SJoseph Chen 	return 0;
3973fb84000SJoseph Chen }
3983fb84000SJoseph Chen 
399b398a9a7SJoseph Chen UCLASS_DRIVER(key) = {
400b398a9a7SJoseph Chen 	.id		= UCLASS_KEY,
401b398a9a7SJoseph Chen 	.name		= "key",
4025a54baa7SJoseph Chen 	.post_probe	= key_post_probe,
4035a54baa7SJoseph Chen 	.per_device_platdata_auto_alloc_size =
4045a54baa7SJoseph Chen 			sizeof(struct dm_key_uclass_platdata),
405b398a9a7SJoseph Chen };
406