xref: /rk3399_rockchip-uboot/drivers/input/key-uclass.c (revision a6c9ff8691383a19143bc7d99d254cffe997e9a3)
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
429b0d00c5SJoseph 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);
549b0d00c5SJoseph 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) {
659b0d00c5SJoseph Chen 		if (adc_raw_to_mV(dev, adcval, &val))
6615da1b50SJoseph Chen 			return KEY_PRESS_NONE;
6715da1b50SJoseph Chen 	}
6815da1b50SJoseph Chen 
699b0d00c5SJoseph 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);
150*a6c9ff86SJoseph Chen 		if (ret)
151*a6c9ff86SJoseph Chen 			ret = uclass_get_device_by_name(UCLASS_ADC, "adc", &dev);
15215da1b50SJoseph Chen 		if (ret) {
15315da1b50SJoseph Chen 			KEY_ERR("%s: No saradc\n", uc_key->name);
1545a54baa7SJoseph Chen 			return KEY_NOT_EXIST;
15564048c53SJoseph Chen 		}
15664048c53SJoseph Chen 
15715da1b50SJoseph Chen 		ret = adc_start_channel(dev, uc_key->channel);
15815da1b50SJoseph Chen 		if (ret) {
15915da1b50SJoseph Chen 			KEY_ERR("%s: Failed to start saradc\n", uc_key->name);
16015da1b50SJoseph Chen 			return KEY_NOT_EXIST;
16115da1b50SJoseph Chen 		}
16215da1b50SJoseph Chen 
16315da1b50SJoseph Chen 		ret = adc_channel_data(dev, uc_key->channel, &adcval);
16415da1b50SJoseph Chen 		if (ret) {
16515da1b50SJoseph Chen 			KEY_ERR("%s: Failed to read saradc, %d\n", uc_key->name, ret);
16615da1b50SJoseph Chen 			return KEY_NOT_EXIST;
16715da1b50SJoseph Chen 		}
16815da1b50SJoseph Chen 
16915da1b50SJoseph Chen 		return key_adc_event(dev, uc_key, adcval);
170eb104afcSJoseph Chen #else
171eb104afcSJoseph Chen 		return KEY_NOT_EXIST;
172eb104afcSJoseph Chen #endif
1735a54baa7SJoseph Chen 	}
17464048c53SJoseph Chen 
1755a54baa7SJoseph Chen 	return (uc_key->code == KEY_POWER) ?
1765a54baa7SJoseph Chen 		key_gpio_interrupt_event(uc_key) :
1775a54baa7SJoseph Chen 		key_gpio_event(uc_key);
1789f1dd9dfSJoseph Chen }
1799f1dd9dfSJoseph Chen 
1809f1dd9dfSJoseph Chen int key_read(int code)
1819f1dd9dfSJoseph Chen {
1825a54baa7SJoseph Chen 	struct dm_key_uclass_platdata *uc_key;
1839f1dd9dfSJoseph Chen 	struct udevice *dev;
1845a54baa7SJoseph Chen 	struct uclass *uc;
1855a54baa7SJoseph Chen 	bool allow_pre_reloc = false;
1865a54baa7SJoseph Chen 	int ret, event = KEY_NOT_EXIST;
1879f1dd9dfSJoseph Chen 
1885a54baa7SJoseph Chen 	ret = uclass_get(UCLASS_KEY, &uc);
1895a54baa7SJoseph Chen 	if (ret)
1905a54baa7SJoseph Chen 		return ret;
1915a54baa7SJoseph Chen 
1925a54baa7SJoseph Chen try_again:
1939f1dd9dfSJoseph Chen 	for (uclass_first_device(UCLASS_KEY, &dev);
1949f1dd9dfSJoseph Chen 	     dev;
1959f1dd9dfSJoseph Chen 	     uclass_next_device(&dev)) {
1965a54baa7SJoseph Chen 		uc_key = dev_get_uclass_platdata(dev);
1979f1dd9dfSJoseph Chen 
1985a54baa7SJoseph Chen 		if (!allow_pre_reloc && uc_key->pre_reloc)
1999f1dd9dfSJoseph Chen 			continue;
2009f1dd9dfSJoseph Chen 
2015a54baa7SJoseph Chen 		if (uc_key->code != code)
2029f1dd9dfSJoseph Chen 			continue;
2039f1dd9dfSJoseph Chen 
2045a54baa7SJoseph Chen 		event = key_core_read(uc_key);
2055a54baa7SJoseph Chen 		if (key_is_pressed(event))
2065a54baa7SJoseph Chen 			return event;
2075a54baa7SJoseph Chen 	}
2085a54baa7SJoseph Chen 
2095a54baa7SJoseph Chen 	/* If not find valid key node from kernel, try from u-boot */
2105a54baa7SJoseph Chen 	if (event == KEY_NOT_EXIST && !allow_pre_reloc) {
2115a54baa7SJoseph Chen 		allow_pre_reloc = true;
2125a54baa7SJoseph Chen 		goto try_again;
2135a54baa7SJoseph Chen 	}
2145a54baa7SJoseph Chen 
2155a54baa7SJoseph Chen 	return event;
2165a54baa7SJoseph Chen }
2175a54baa7SJoseph Chen 
21818fdcbceSJoseph Chen int key_exist(int code)
21918fdcbceSJoseph Chen {
22018fdcbceSJoseph Chen 	struct dm_key_uclass_platdata *uc_key;
22118fdcbceSJoseph Chen 	struct udevice *dev;
22218fdcbceSJoseph Chen 
22318fdcbceSJoseph Chen 	for (uclass_find_first_device(UCLASS_KEY, &dev);
22418fdcbceSJoseph Chen 	     dev;
22518fdcbceSJoseph Chen 	     uclass_find_next_device(&dev)) {
22618fdcbceSJoseph Chen 		uc_key = dev_get_uclass_platdata(dev);
22718fdcbceSJoseph Chen 
22818fdcbceSJoseph Chen 		if (uc_key->code == code)
22918fdcbceSJoseph Chen 			return 1;
23018fdcbceSJoseph Chen 	}
23118fdcbceSJoseph Chen 
23218fdcbceSJoseph Chen 	return 0;
23318fdcbceSJoseph Chen }
23418fdcbceSJoseph Chen 
2357cef7918SJoseph Chen #if CONFIG_IS_ENABLED(IRQ)
2361a9c8b1bSJoseph Chen #if defined(CONFIG_PWRKEY_DNL_TRIGGER_NUM) && \
2371a9c8b1bSJoseph Chen 		(CONFIG_PWRKEY_DNL_TRIGGER_NUM > 0)
2381a9c8b1bSJoseph Chen static void power_key_download(struct dm_key_uclass_platdata *uc_key)
2391a9c8b1bSJoseph Chen {
2401a9c8b1bSJoseph Chen 	int trig_cnt = CONFIG_PWRKEY_DNL_TRIGGER_NUM;
2411a9c8b1bSJoseph Chen 	static u64 old_rise_ms;
2421a9c8b1bSJoseph Chen 
2431a9c8b1bSJoseph Chen 	if (uc_key->code == KEY_POWER && old_rise_ms != uc_key->rise_ms) {
2441a9c8b1bSJoseph Chen 		old_rise_ms = uc_key->rise_ms;
2451a9c8b1bSJoseph Chen 		uc_key->trig_cnt++;
2461a9c8b1bSJoseph Chen 		if (uc_key->trig_cnt >= trig_cnt) {
2471a9c8b1bSJoseph Chen 			printf("\nEnter download mode by pwrkey\n");
2481a9c8b1bSJoseph Chen 			irq_handler_disable(uc_key->irq);
249b40ac3b4SJoseph Chen 			run_command("download", 0);
2501a9c8b1bSJoseph Chen 		}
2511a9c8b1bSJoseph Chen 	}
2521a9c8b1bSJoseph Chen }
2531a9c8b1bSJoseph Chen 
2541a9c8b1bSJoseph Chen int pwrkey_download_init(void)
2551a9c8b1bSJoseph Chen {
2561a9c8b1bSJoseph Chen 	return (KEY_NOT_EXIST == key_read(KEY_POWER));
2571a9c8b1bSJoseph Chen }
2581a9c8b1bSJoseph Chen #endif
2591a9c8b1bSJoseph Chen 
2605a54baa7SJoseph Chen static void gpio_irq_handler(int irq, void *data)
2615a54baa7SJoseph Chen {
262c2e7a0d4SJoseph Chen 	struct udevice *dev = data;
263c2e7a0d4SJoseph Chen 	struct dm_key_uclass_platdata *uc_key = dev_get_uclass_platdata(dev);
2645a54baa7SJoseph Chen 
2655a54baa7SJoseph Chen 	if (uc_key->irq != irq)
2665a54baa7SJoseph Chen 		return;
2675a54baa7SJoseph Chen 
268c2e7a0d4SJoseph Chen 	if (uc_key->irq_thread) {
269c2e7a0d4SJoseph Chen 		uc_key->irq_thread(irq, data);
270c2e7a0d4SJoseph Chen 	} else {
2715a54baa7SJoseph Chen 		if (irq_get_gpio_level(irq)) {
2725a54baa7SJoseph Chen 			uc_key->rise_ms = key_timer(0);
273c2e7a0d4SJoseph Chen 			KEY_DBG("%s: key dn: %llu ms\n",
274c2e7a0d4SJoseph Chen 				uc_key->name, uc_key->fall_ms);
2755a54baa7SJoseph Chen 		} else {
2765a54baa7SJoseph Chen 			uc_key->fall_ms = key_timer(0);
277c2e7a0d4SJoseph Chen 			KEY_DBG("%s: key up: %llu ms\n",
278c2e7a0d4SJoseph Chen 				uc_key->name, uc_key->rise_ms);
2795a54baa7SJoseph Chen 		}
2805a54baa7SJoseph Chen 
2815a54baa7SJoseph Chen 		/* Must delay */
2825a54baa7SJoseph Chen 		mdelay(10);
2835a54baa7SJoseph Chen 		irq_revert_irq_type(irq);
2845a54baa7SJoseph Chen 	}
2851a9c8b1bSJoseph Chen 
2861a9c8b1bSJoseph Chen 	/* Hook event: enter download mode by pwrkey */
2871a9c8b1bSJoseph Chen #if defined(CONFIG_PWRKEY_DNL_TRIGGER_NUM) && \
2881a9c8b1bSJoseph Chen 		(CONFIG_PWRKEY_DNL_TRIGGER_NUM > 0)
2891a9c8b1bSJoseph Chen 	power_key_download(uc_key);
2901a9c8b1bSJoseph Chen #endif
291c2e7a0d4SJoseph Chen }
2925a54baa7SJoseph Chen #endif
2935a54baa7SJoseph Chen 
2945a54baa7SJoseph Chen int key_bind_children(struct udevice *dev, const char *drv_name)
2955a54baa7SJoseph Chen {
2965a54baa7SJoseph Chen 	const char *name;
2975a54baa7SJoseph Chen 	ofnode node;
2985a54baa7SJoseph Chen 	int ret;
2995a54baa7SJoseph Chen 
3005a54baa7SJoseph Chen 	dev_for_each_subnode(node, dev) {
3015a54baa7SJoseph Chen 		/*
3025a54baa7SJoseph Chen 		 * If this node has "compatible" property, this is not
3035a54baa7SJoseph Chen 		 * a amp subnode, but a normal device. skip.
3045a54baa7SJoseph Chen 		 */
3055a54baa7SJoseph Chen 		ofnode_get_property(node, "compatible", &ret);
3065a54baa7SJoseph Chen 		if (ret >= 0)
3075a54baa7SJoseph Chen 			continue;
3085a54baa7SJoseph Chen 
3095a54baa7SJoseph Chen 		if (ret != -FDT_ERR_NOTFOUND)
3105a54baa7SJoseph Chen 			return ret;
3115a54baa7SJoseph Chen 
3125a54baa7SJoseph Chen 		name = ofnode_get_name(node);
3135a54baa7SJoseph Chen 		if (!name)
3145a54baa7SJoseph Chen 			return -EINVAL;
3155a54baa7SJoseph Chen 		ret = device_bind_driver_to_node(dev, drv_name, name,
3165a54baa7SJoseph Chen 						 node, NULL);
3175a54baa7SJoseph Chen 		if (ret)
3185a54baa7SJoseph Chen 			return ret;
3195a54baa7SJoseph Chen 	}
3205a54baa7SJoseph Chen 
3215a54baa7SJoseph Chen 	return 0;
3225a54baa7SJoseph Chen }
3235a54baa7SJoseph Chen 
3245a54baa7SJoseph Chen static int key_post_probe(struct udevice *dev)
3255a54baa7SJoseph Chen {
3265a54baa7SJoseph Chen 	struct dm_key_uclass_platdata *uc_key;
3275a54baa7SJoseph Chen 	int ret;
32815da1b50SJoseph Chen 
3295a54baa7SJoseph Chen 	uc_key = dev_get_uclass_platdata(dev);
3305a54baa7SJoseph Chen 	if (!uc_key)
3315a54baa7SJoseph Chen 		return -ENXIO;
3325a54baa7SJoseph Chen 
3335a54baa7SJoseph Chen 	/* True from U-Boot key node */
334930ceb12SJoseph Chen 	uc_key->pre_reloc = dev_read_bool(dev, "u-boot,dm-pre-reloc") ||
335930ceb12SJoseph Chen 			    dev_read_bool(dev, "u-boot,dm-spl");
3365a54baa7SJoseph Chen 
33715da1b50SJoseph Chen 	if (uc_key->type != ADC_KEY) {
3385a54baa7SJoseph Chen 		if (uc_key->code == KEY_POWER) {
3397cef7918SJoseph Chen #if CONFIG_IS_ENABLED(IRQ)
3405a54baa7SJoseph Chen 			int irq;
3415a54baa7SJoseph Chen 
3420f9d23eaSJoseph Chen 			if (uc_key->skip_irq_init)
3430f9d23eaSJoseph Chen 				return 0;
3440f9d23eaSJoseph Chen 
3455a54baa7SJoseph Chen 			irq = phandle_gpio_to_irq(uc_key->gpios[0],
3465a54baa7SJoseph Chen 						  uc_key->gpios[1]);
3475a54baa7SJoseph Chen 			if (irq < 0) {
3485a54baa7SJoseph Chen 				KEY_ERR("%s: failed to request irq, ret=%d\n",
3495a54baa7SJoseph Chen 					uc_key->name, irq);
3505a54baa7SJoseph Chen 				return irq;
3515a54baa7SJoseph Chen 			}
3525a54baa7SJoseph Chen 
353c2e7a0d4SJoseph Chen 			if (uc_key->code != KEY_POWER && uc_key->irq_thread) {
354c2e7a0d4SJoseph Chen 				KEY_WARN("%s: only power key can request irq thread\n",
355c2e7a0d4SJoseph Chen 					 uc_key->name);
356c2e7a0d4SJoseph Chen 				return -EINVAL;
357c2e7a0d4SJoseph Chen 			}
358c2e7a0d4SJoseph Chen 
3595a54baa7SJoseph Chen 			uc_key->irq = irq;
360c2e7a0d4SJoseph Chen 			irq_install_handler(irq, gpio_irq_handler, dev);
3615a54baa7SJoseph Chen 			irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
3625a54baa7SJoseph Chen 			irq_handler_enable(irq);
3635a54baa7SJoseph Chen #else
3645a54baa7SJoseph Chen 			KEY_WARN("%s: no IRQ framework available\n", uc_key->name);
3655a54baa7SJoseph Chen #endif
3665a54baa7SJoseph Chen 		} else {
3675a54baa7SJoseph Chen 			ret = gpio_request_by_name(dev, "gpios", 0,
3685a54baa7SJoseph Chen 						   &uc_key->gpio, GPIOD_IS_IN);
3695a54baa7SJoseph Chen 			if (ret) {
3705a54baa7SJoseph Chen 				KEY_ERR("%s: failed to request gpio, ret=%d\n",
3715a54baa7SJoseph Chen 					uc_key->name, ret);
3725a54baa7SJoseph Chen 				return ret;
3735a54baa7SJoseph Chen 			}
3749f1dd9dfSJoseph Chen 		}
375adba3792SJoseph Chen 	}
376adba3792SJoseph Chen 
3775a54baa7SJoseph Chen #ifdef DEBUG
3785a54baa7SJoseph Chen 	printf("[%s] (%s, %s, %s):\n", uc_key->name,
3795a54baa7SJoseph Chen 	       uc_key->type == ADC_KEY ? "ADC" : "GPIO",
3805a54baa7SJoseph Chen 	       uc_key->pre_reloc ? "U-Boot" : "Kernel",
3815a54baa7SJoseph Chen 	       dev->parent->name);
3825a54baa7SJoseph Chen 
3835a54baa7SJoseph Chen 	if (uc_key->type == ADC_KEY) {
38415da1b50SJoseph Chen 		printf("      %s: %d (%d, %d)\n",
38515da1b50SJoseph Chen 		       uc_key->in_volt ? "volt" : " adc",
38615da1b50SJoseph Chen 		       uc_key->center, uc_key->min, uc_key->max);
3875a54baa7SJoseph Chen 		printf("   channel: %d\n\n", uc_key->channel);
3885a54baa7SJoseph Chen 	} else {
3895a54baa7SJoseph Chen 		const char *gpio_name =
3905a54baa7SJoseph Chen 		     ofnode_get_name(ofnode_get_by_phandle(uc_key->gpios[0]));
3915a54baa7SJoseph Chen 
3925a54baa7SJoseph Chen 		printf("       irq: %d\n", uc_key->irq);
3935a54baa7SJoseph Chen 		printf("   gpio[0]: %s\n", gpio_name);
3945a54baa7SJoseph Chen 		printf("   gpio[1]: %d\n\n", uc_key->gpios[1]);
3955a54baa7SJoseph Chen 	}
3965a54baa7SJoseph Chen #endif
3975a54baa7SJoseph Chen 
3985a54baa7SJoseph Chen 	return 0;
3993fb84000SJoseph Chen }
4003fb84000SJoseph Chen 
401b398a9a7SJoseph Chen UCLASS_DRIVER(key) = {
402b398a9a7SJoseph Chen 	.id		= UCLASS_KEY,
403b398a9a7SJoseph Chen 	.name		= "key",
4045a54baa7SJoseph Chen 	.post_probe	= key_post_probe,
4055a54baa7SJoseph Chen 	.per_device_platdata_auto_alloc_size =
4065a54baa7SJoseph Chen 			sizeof(struct dm_key_uclass_platdata),
407b398a9a7SJoseph Chen };
408