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
16*6c92fe84SJoseph Chen DECLARE_GLOBAL_DATA_PTR;
17*6c92fe84SJoseph Chen
185a54baa7SJoseph Chen #define KEY_WARN(fmt, args...) printf("Key Warn: "fmt, ##args)
195a54baa7SJoseph Chen #define KEY_ERR(fmt, args...) printf("Key Error: "fmt, ##args)
205a54baa7SJoseph Chen #define KEY_DBG(fmt, args...) debug("Key Debug: "fmt, ##args)
21adba3792SJoseph Chen
arch_counter_get_cntpct(void)22a2df9606SJoseph Chen static inline uint64_t arch_counter_get_cntpct(void)
23a2df9606SJoseph Chen {
24a2df9606SJoseph Chen uint64_t cval = 0;
25a2df9606SJoseph Chen
26a2df9606SJoseph Chen isb();
27a2df9606SJoseph Chen #ifdef CONFIG_ARM64
28a2df9606SJoseph Chen asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
29a2df9606SJoseph Chen #else
30a2df9606SJoseph Chen asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
31a2df9606SJoseph Chen #endif
32a2df9606SJoseph Chen return cval;
33a2df9606SJoseph Chen }
34a2df9606SJoseph Chen
key_timer(uint64_t base)3564048c53SJoseph Chen uint64_t key_timer(uint64_t base)
36a2df9606SJoseph Chen {
37a2df9606SJoseph Chen uint64_t cntpct;
38a2df9606SJoseph Chen
39*6c92fe84SJoseph Chen cntpct = arch_counter_get_cntpct() / (gd->arch.timer_rate_hz / 1000);
40a2df9606SJoseph Chen return (cntpct > base) ? (cntpct - base) : 0;
41a2df9606SJoseph Chen }
42a2df9606SJoseph Chen
43eb104afcSJoseph Chen #ifdef CONFIG_ADC
adc_raw_to_mV(struct udevice * dev,unsigned int raw,int * mV)449b0d00c5SJoseph Chen static int adc_raw_to_mV(struct udevice *dev, unsigned int raw, int *mV)
45a2df9606SJoseph Chen {
4615da1b50SJoseph Chen unsigned int data_mask;
4715da1b50SJoseph Chen int ret, vref = 1800000;
4815da1b50SJoseph Chen u64 raw64 = raw;
4915da1b50SJoseph Chen
5015da1b50SJoseph Chen ret = adc_data_mask(dev, &data_mask);
5115da1b50SJoseph Chen if (ret)
5215da1b50SJoseph Chen return ret;
5315da1b50SJoseph Chen
5415da1b50SJoseph Chen raw64 *= vref;
5515da1b50SJoseph Chen do_div(raw64, data_mask);
569b0d00c5SJoseph Chen *mV = raw64;
5715da1b50SJoseph Chen
5815da1b50SJoseph Chen return 0;
5915da1b50SJoseph Chen }
6015da1b50SJoseph Chen
key_adc_event(struct udevice * dev,struct dm_key_uclass_platdata * uc_key,int adcval)6115da1b50SJoseph Chen static int key_adc_event(struct udevice *dev,
6215da1b50SJoseph Chen struct dm_key_uclass_platdata *uc_key, int adcval)
6315da1b50SJoseph Chen {
6415da1b50SJoseph Chen int val = adcval;
6515da1b50SJoseph Chen
6615da1b50SJoseph Chen if (uc_key->in_volt) {
679b0d00c5SJoseph Chen if (adc_raw_to_mV(dev, adcval, &val))
6815da1b50SJoseph Chen return KEY_PRESS_NONE;
6915da1b50SJoseph Chen }
7015da1b50SJoseph Chen
719b0d00c5SJoseph Chen debug("[%s] <%d, %d, %d>: adcval=%d -> mV=%d\n",
7215da1b50SJoseph Chen uc_key->name, uc_key->min, uc_key->center, uc_key->max,
7315da1b50SJoseph Chen adcval, val);
7415da1b50SJoseph Chen
7515da1b50SJoseph Chen return (val <= uc_key->max && val >= uc_key->min) ?
765a54baa7SJoseph Chen KEY_PRESS_DOWN : KEY_PRESS_NONE;
773fb84000SJoseph Chen }
78eb104afcSJoseph Chen #endif
793fb84000SJoseph Chen
key_gpio_event(struct dm_key_uclass_platdata * uc_key)805a54baa7SJoseph Chen static int key_gpio_event(struct dm_key_uclass_platdata *uc_key)
813fb84000SJoseph Chen {
825a54baa7SJoseph Chen if (!dm_gpio_is_valid(&uc_key->gpio)) {
835a54baa7SJoseph Chen KEY_ERR("'%s' Invalid gpio\n", uc_key->name);
8464048c53SJoseph Chen return KEY_PRESS_NONE;
8564048c53SJoseph Chen }
8664048c53SJoseph Chen
875a54baa7SJoseph Chen return dm_gpio_get_value(&uc_key->gpio) ?
885a54baa7SJoseph Chen KEY_PRESS_DOWN : KEY_PRESS_NONE;
8964048c53SJoseph Chen }
9064048c53SJoseph Chen
key_gpio_interrupt_event(struct dm_key_uclass_platdata * uc_key)915a54baa7SJoseph Chen static int key_gpio_interrupt_event(struct dm_key_uclass_platdata *uc_key)
9264048c53SJoseph Chen {
935a54baa7SJoseph Chen int event;
943fb84000SJoseph Chen
953fb84000SJoseph Chen debug("%s: %s: up=%llu, down=%llu, delta=%llu\n",
965a54baa7SJoseph Chen __func__, uc_key->name, uc_key->rise_ms, uc_key->fall_ms,
975a54baa7SJoseph Chen uc_key->rise_ms - uc_key->fall_ms);
983fb84000SJoseph Chen
993fb84000SJoseph Chen /* Possible this is machine power-on long pressed, so ignore this */
1005a54baa7SJoseph Chen if (uc_key->fall_ms == 0 && uc_key->rise_ms != 0) {
1015a54baa7SJoseph Chen event = KEY_PRESS_NONE;
1023fb84000SJoseph Chen goto out;
1033fb84000SJoseph Chen }
1043fb84000SJoseph Chen
1055a54baa7SJoseph Chen if ((uc_key->rise_ms > uc_key->fall_ms) &&
1065a54baa7SJoseph Chen (uc_key->rise_ms - uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
1075a54baa7SJoseph Chen uc_key->rise_ms = 0;
1085a54baa7SJoseph Chen uc_key->fall_ms = 0;
1095a54baa7SJoseph Chen event = KEY_PRESS_LONG_DOWN;
1105a54baa7SJoseph Chen KEY_DBG("%s key long pressed..\n", uc_key->name);
1115a54baa7SJoseph Chen } else if (uc_key->fall_ms &&
1125a54baa7SJoseph Chen key_timer(uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
1135a54baa7SJoseph Chen uc_key->rise_ms = 0;
1145a54baa7SJoseph Chen uc_key->fall_ms = 0;
1155a54baa7SJoseph Chen event = KEY_PRESS_LONG_DOWN;
1165a54baa7SJoseph Chen KEY_DBG("%s key long pressed(hold)..\n", uc_key->name);
1175a54baa7SJoseph Chen } else if ((uc_key->rise_ms > uc_key->fall_ms) &&
1185a54baa7SJoseph Chen (uc_key->rise_ms - uc_key->fall_ms) < KEY_LONG_DOWN_MS) {
1195a54baa7SJoseph Chen uc_key->rise_ms = 0;
1205a54baa7SJoseph Chen uc_key->fall_ms = 0;
1215a54baa7SJoseph Chen event = KEY_PRESS_DOWN;
1225a54baa7SJoseph Chen KEY_DBG("%s key short pressed..\n", uc_key->name);
12364048c53SJoseph Chen /* Possible in charge animation, we enable irq after fuel gauge updated */
1245a54baa7SJoseph Chen } else if (uc_key->rise_ms && uc_key->fall_ms &&
1255a54baa7SJoseph Chen (uc_key->rise_ms == uc_key->fall_ms)) {
1265a54baa7SJoseph Chen uc_key->rise_ms = 0;
1275a54baa7SJoseph Chen uc_key->fall_ms = 0;
1285a54baa7SJoseph Chen event = KEY_PRESS_DOWN;
1295a54baa7SJoseph Chen KEY_DBG("%s key short pressed..\n", uc_key->name);
1303fb84000SJoseph Chen } else {
1315a54baa7SJoseph Chen event = KEY_PRESS_NONE;
1323fb84000SJoseph Chen }
1333fb84000SJoseph Chen
1343fb84000SJoseph Chen out:
1355a54baa7SJoseph Chen return event;
13664048c53SJoseph Chen }
13764048c53SJoseph Chen
key_is_pressed(int event)1385a54baa7SJoseph Chen int key_is_pressed(int event)
13964048c53SJoseph Chen {
1405a54baa7SJoseph Chen return (event == KEY_PRESS_DOWN || event == KEY_PRESS_LONG_DOWN);
14164048c53SJoseph Chen }
14264048c53SJoseph Chen
key_core_read(struct dm_key_uclass_platdata * uc_key)1435a54baa7SJoseph Chen static int key_core_read(struct dm_key_uclass_platdata *uc_key)
14464048c53SJoseph Chen {
145eb104afcSJoseph Chen if (uc_key->type == ADC_KEY) {
146eb104afcSJoseph Chen #ifdef CONFIG_ADC
14715da1b50SJoseph Chen struct udevice *dev;
14864048c53SJoseph Chen unsigned int adcval;
14915da1b50SJoseph Chen int ret;
15064048c53SJoseph Chen
15115da1b50SJoseph Chen ret = uclass_get_device_by_name(UCLASS_ADC, "saradc", &dev);
152a6c9ff86SJoseph Chen if (ret)
153a6c9ff86SJoseph Chen ret = uclass_get_device_by_name(UCLASS_ADC, "adc", &dev);
15415da1b50SJoseph Chen if (ret) {
15515da1b50SJoseph Chen KEY_ERR("%s: No saradc\n", uc_key->name);
1565a54baa7SJoseph Chen return KEY_NOT_EXIST;
15764048c53SJoseph Chen }
15864048c53SJoseph Chen
15915da1b50SJoseph Chen ret = adc_start_channel(dev, uc_key->channel);
16015da1b50SJoseph Chen if (ret) {
16115da1b50SJoseph Chen KEY_ERR("%s: Failed to start saradc\n", uc_key->name);
16215da1b50SJoseph Chen return KEY_NOT_EXIST;
16315da1b50SJoseph Chen }
16415da1b50SJoseph Chen
16515da1b50SJoseph Chen ret = adc_channel_data(dev, uc_key->channel, &adcval);
16615da1b50SJoseph Chen if (ret) {
16715da1b50SJoseph Chen KEY_ERR("%s: Failed to read saradc, %d\n", uc_key->name, ret);
16815da1b50SJoseph Chen return KEY_NOT_EXIST;
16915da1b50SJoseph Chen }
17015da1b50SJoseph Chen
17115da1b50SJoseph Chen return key_adc_event(dev, uc_key, adcval);
172eb104afcSJoseph Chen #else
173eb104afcSJoseph Chen return KEY_NOT_EXIST;
174eb104afcSJoseph Chen #endif
1755a54baa7SJoseph Chen }
17664048c53SJoseph Chen
1775a54baa7SJoseph Chen return (uc_key->code == KEY_POWER) ?
1785a54baa7SJoseph Chen key_gpio_interrupt_event(uc_key) :
1795a54baa7SJoseph Chen key_gpio_event(uc_key);
1809f1dd9dfSJoseph Chen }
1819f1dd9dfSJoseph Chen
key_read(int code)1829f1dd9dfSJoseph Chen int key_read(int code)
1839f1dd9dfSJoseph Chen {
1845a54baa7SJoseph Chen struct dm_key_uclass_platdata *uc_key;
1859f1dd9dfSJoseph Chen struct udevice *dev;
1865a54baa7SJoseph Chen struct uclass *uc;
1875a54baa7SJoseph Chen bool allow_pre_reloc = false;
1885a54baa7SJoseph Chen int ret, event = KEY_NOT_EXIST;
1899f1dd9dfSJoseph Chen
1905a54baa7SJoseph Chen ret = uclass_get(UCLASS_KEY, &uc);
1915a54baa7SJoseph Chen if (ret)
1925a54baa7SJoseph Chen return ret;
1935a54baa7SJoseph Chen
1945a54baa7SJoseph Chen try_again:
1959f1dd9dfSJoseph Chen for (uclass_first_device(UCLASS_KEY, &dev);
1969f1dd9dfSJoseph Chen dev;
1979f1dd9dfSJoseph Chen uclass_next_device(&dev)) {
1985a54baa7SJoseph Chen uc_key = dev_get_uclass_platdata(dev);
1999f1dd9dfSJoseph Chen
2005a54baa7SJoseph Chen if (!allow_pre_reloc && uc_key->pre_reloc)
2019f1dd9dfSJoseph Chen continue;
2029f1dd9dfSJoseph Chen
2035a54baa7SJoseph Chen if (uc_key->code != code)
2049f1dd9dfSJoseph Chen continue;
2059f1dd9dfSJoseph Chen
2065a54baa7SJoseph Chen event = key_core_read(uc_key);
2075a54baa7SJoseph Chen if (key_is_pressed(event))
2085a54baa7SJoseph Chen return event;
2095a54baa7SJoseph Chen }
2105a54baa7SJoseph Chen
2115a54baa7SJoseph Chen /* If not find valid key node from kernel, try from u-boot */
2125a54baa7SJoseph Chen if (event == KEY_NOT_EXIST && !allow_pre_reloc) {
2135a54baa7SJoseph Chen allow_pre_reloc = true;
2145a54baa7SJoseph Chen goto try_again;
2155a54baa7SJoseph Chen }
2165a54baa7SJoseph Chen
2175a54baa7SJoseph Chen return event;
2185a54baa7SJoseph Chen }
2195a54baa7SJoseph Chen
key_exist(int code)22018fdcbceSJoseph Chen int key_exist(int code)
22118fdcbceSJoseph Chen {
22218fdcbceSJoseph Chen struct dm_key_uclass_platdata *uc_key;
22318fdcbceSJoseph Chen struct udevice *dev;
22418fdcbceSJoseph Chen
22518fdcbceSJoseph Chen for (uclass_find_first_device(UCLASS_KEY, &dev);
22618fdcbceSJoseph Chen dev;
22718fdcbceSJoseph Chen uclass_find_next_device(&dev)) {
22818fdcbceSJoseph Chen uc_key = dev_get_uclass_platdata(dev);
22918fdcbceSJoseph Chen
23018fdcbceSJoseph Chen if (uc_key->code == code)
23118fdcbceSJoseph Chen return 1;
23218fdcbceSJoseph Chen }
23318fdcbceSJoseph Chen
23418fdcbceSJoseph Chen return 0;
23518fdcbceSJoseph Chen }
23618fdcbceSJoseph Chen
2377cef7918SJoseph Chen #if CONFIG_IS_ENABLED(IRQ)
2381a9c8b1bSJoseph Chen #if defined(CONFIG_PWRKEY_DNL_TRIGGER_NUM) && \
2391a9c8b1bSJoseph Chen (CONFIG_PWRKEY_DNL_TRIGGER_NUM > 0)
power_key_download(struct dm_key_uclass_platdata * uc_key)2401a9c8b1bSJoseph Chen static void power_key_download(struct dm_key_uclass_platdata *uc_key)
2411a9c8b1bSJoseph Chen {
2421a9c8b1bSJoseph Chen int trig_cnt = CONFIG_PWRKEY_DNL_TRIGGER_NUM;
2431a9c8b1bSJoseph Chen static u64 old_rise_ms;
2441a9c8b1bSJoseph Chen
2451a9c8b1bSJoseph Chen if (uc_key->code == KEY_POWER && old_rise_ms != uc_key->rise_ms) {
2461a9c8b1bSJoseph Chen old_rise_ms = uc_key->rise_ms;
2471a9c8b1bSJoseph Chen uc_key->trig_cnt++;
2481a9c8b1bSJoseph Chen if (uc_key->trig_cnt >= trig_cnt) {
2491a9c8b1bSJoseph Chen printf("\nEnter download mode by pwrkey\n");
2501a9c8b1bSJoseph Chen irq_handler_disable(uc_key->irq);
251b40ac3b4SJoseph Chen run_command("download", 0);
2521a9c8b1bSJoseph Chen }
2531a9c8b1bSJoseph Chen }
2541a9c8b1bSJoseph Chen }
2551a9c8b1bSJoseph Chen
pwrkey_download_init(void)2561a9c8b1bSJoseph Chen int pwrkey_download_init(void)
2571a9c8b1bSJoseph Chen {
2581a9c8b1bSJoseph Chen return (KEY_NOT_EXIST == key_read(KEY_POWER));
2591a9c8b1bSJoseph Chen }
2601a9c8b1bSJoseph Chen #endif
2611a9c8b1bSJoseph Chen
gpio_irq_handler(int irq,void * data)2625a54baa7SJoseph Chen static void gpio_irq_handler(int irq, void *data)
2635a54baa7SJoseph Chen {
264c2e7a0d4SJoseph Chen struct udevice *dev = data;
265c2e7a0d4SJoseph Chen struct dm_key_uclass_platdata *uc_key = dev_get_uclass_platdata(dev);
2665a54baa7SJoseph Chen
2675a54baa7SJoseph Chen if (uc_key->irq != irq)
2685a54baa7SJoseph Chen return;
2695a54baa7SJoseph Chen
270c2e7a0d4SJoseph Chen if (uc_key->irq_thread) {
271c2e7a0d4SJoseph Chen uc_key->irq_thread(irq, data);
272c2e7a0d4SJoseph Chen } else {
2735a54baa7SJoseph Chen if (irq_get_gpio_level(irq)) {
2745a54baa7SJoseph Chen uc_key->rise_ms = key_timer(0);
275c2e7a0d4SJoseph Chen KEY_DBG("%s: key dn: %llu ms\n",
276c2e7a0d4SJoseph Chen uc_key->name, uc_key->fall_ms);
2775a54baa7SJoseph Chen } else {
2785a54baa7SJoseph Chen uc_key->fall_ms = key_timer(0);
279c2e7a0d4SJoseph Chen KEY_DBG("%s: key up: %llu ms\n",
280c2e7a0d4SJoseph Chen uc_key->name, uc_key->rise_ms);
2815a54baa7SJoseph Chen }
2825a54baa7SJoseph Chen
2835a54baa7SJoseph Chen /* Must delay */
2845a54baa7SJoseph Chen mdelay(10);
2855a54baa7SJoseph Chen irq_revert_irq_type(irq);
2865a54baa7SJoseph Chen }
2871a9c8b1bSJoseph Chen
2881a9c8b1bSJoseph Chen /* Hook event: enter download mode by pwrkey */
2891a9c8b1bSJoseph Chen #if defined(CONFIG_PWRKEY_DNL_TRIGGER_NUM) && \
2901a9c8b1bSJoseph Chen (CONFIG_PWRKEY_DNL_TRIGGER_NUM > 0)
2911a9c8b1bSJoseph Chen power_key_download(uc_key);
2921a9c8b1bSJoseph Chen #endif
293c2e7a0d4SJoseph Chen }
2945a54baa7SJoseph Chen #endif
2955a54baa7SJoseph Chen
key_bind_children(struct udevice * dev,const char * drv_name)2965a54baa7SJoseph Chen int key_bind_children(struct udevice *dev, const char *drv_name)
2975a54baa7SJoseph Chen {
2985a54baa7SJoseph Chen const char *name;
2995a54baa7SJoseph Chen ofnode node;
3005a54baa7SJoseph Chen int ret;
3015a54baa7SJoseph Chen
3025a54baa7SJoseph Chen dev_for_each_subnode(node, dev) {
3035a54baa7SJoseph Chen /*
3045a54baa7SJoseph Chen * If this node has "compatible" property, this is not
3055a54baa7SJoseph Chen * a amp subnode, but a normal device. skip.
3065a54baa7SJoseph Chen */
3075a54baa7SJoseph Chen ofnode_get_property(node, "compatible", &ret);
3085a54baa7SJoseph Chen if (ret >= 0)
3095a54baa7SJoseph Chen continue;
3105a54baa7SJoseph Chen
3115a54baa7SJoseph Chen if (ret != -FDT_ERR_NOTFOUND)
3125a54baa7SJoseph Chen return ret;
3135a54baa7SJoseph Chen
3145a54baa7SJoseph Chen name = ofnode_get_name(node);
3155a54baa7SJoseph Chen if (!name)
3165a54baa7SJoseph Chen return -EINVAL;
3175a54baa7SJoseph Chen ret = device_bind_driver_to_node(dev, drv_name, name,
3185a54baa7SJoseph Chen node, NULL);
3195a54baa7SJoseph Chen if (ret)
3205a54baa7SJoseph Chen return ret;
3215a54baa7SJoseph Chen }
3225a54baa7SJoseph Chen
3235a54baa7SJoseph Chen return 0;
3245a54baa7SJoseph Chen }
3255a54baa7SJoseph Chen
key_post_probe(struct udevice * dev)3265a54baa7SJoseph Chen static int key_post_probe(struct udevice *dev)
3275a54baa7SJoseph Chen {
3285a54baa7SJoseph Chen struct dm_key_uclass_platdata *uc_key;
3295a54baa7SJoseph Chen int ret;
33015da1b50SJoseph Chen
3315a54baa7SJoseph Chen uc_key = dev_get_uclass_platdata(dev);
3325a54baa7SJoseph Chen if (!uc_key)
3335a54baa7SJoseph Chen return -ENXIO;
3345a54baa7SJoseph Chen
3355a54baa7SJoseph Chen /* True from U-Boot key node */
336930ceb12SJoseph Chen uc_key->pre_reloc = dev_read_bool(dev, "u-boot,dm-pre-reloc") ||
337930ceb12SJoseph Chen dev_read_bool(dev, "u-boot,dm-spl");
3385a54baa7SJoseph Chen
33915da1b50SJoseph Chen if (uc_key->type != ADC_KEY) {
3405a54baa7SJoseph Chen if (uc_key->code == KEY_POWER) {
3417cef7918SJoseph Chen #if CONFIG_IS_ENABLED(IRQ)
3425a54baa7SJoseph Chen int irq;
3435a54baa7SJoseph Chen
3440f9d23eaSJoseph Chen if (uc_key->skip_irq_init)
3450f9d23eaSJoseph Chen return 0;
3460f9d23eaSJoseph Chen
3475a54baa7SJoseph Chen irq = phandle_gpio_to_irq(uc_key->gpios[0],
3485a54baa7SJoseph Chen uc_key->gpios[1]);
3495a54baa7SJoseph Chen if (irq < 0) {
3505a54baa7SJoseph Chen KEY_ERR("%s: failed to request irq, ret=%d\n",
3515a54baa7SJoseph Chen uc_key->name, irq);
3525a54baa7SJoseph Chen return irq;
3535a54baa7SJoseph Chen }
3545a54baa7SJoseph Chen
355c2e7a0d4SJoseph Chen if (uc_key->code != KEY_POWER && uc_key->irq_thread) {
356c2e7a0d4SJoseph Chen KEY_WARN("%s: only power key can request irq thread\n",
357c2e7a0d4SJoseph Chen uc_key->name);
358c2e7a0d4SJoseph Chen return -EINVAL;
359c2e7a0d4SJoseph Chen }
360c2e7a0d4SJoseph Chen
3615a54baa7SJoseph Chen uc_key->irq = irq;
362c2e7a0d4SJoseph Chen irq_install_handler(irq, gpio_irq_handler, dev);
3635a54baa7SJoseph Chen irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
3645a54baa7SJoseph Chen irq_handler_enable(irq);
3655a54baa7SJoseph Chen #else
3665a54baa7SJoseph Chen KEY_WARN("%s: no IRQ framework available\n", uc_key->name);
3675a54baa7SJoseph Chen #endif
3685a54baa7SJoseph Chen } else {
3695a54baa7SJoseph Chen ret = gpio_request_by_name(dev, "gpios", 0,
3705a54baa7SJoseph Chen &uc_key->gpio, GPIOD_IS_IN);
3715a54baa7SJoseph Chen if (ret) {
3725a54baa7SJoseph Chen KEY_ERR("%s: failed to request gpio, ret=%d\n",
3735a54baa7SJoseph Chen uc_key->name, ret);
3745a54baa7SJoseph Chen return ret;
3755a54baa7SJoseph Chen }
3769f1dd9dfSJoseph Chen }
377adba3792SJoseph Chen }
378adba3792SJoseph Chen
3795a54baa7SJoseph Chen #ifdef DEBUG
3805a54baa7SJoseph Chen printf("[%s] (%s, %s, %s):\n", uc_key->name,
3815a54baa7SJoseph Chen uc_key->type == ADC_KEY ? "ADC" : "GPIO",
3825a54baa7SJoseph Chen uc_key->pre_reloc ? "U-Boot" : "Kernel",
3835a54baa7SJoseph Chen dev->parent->name);
3845a54baa7SJoseph Chen
3855a54baa7SJoseph Chen if (uc_key->type == ADC_KEY) {
38615da1b50SJoseph Chen printf(" %s: %d (%d, %d)\n",
38715da1b50SJoseph Chen uc_key->in_volt ? "volt" : " adc",
38815da1b50SJoseph Chen uc_key->center, uc_key->min, uc_key->max);
3895a54baa7SJoseph Chen printf(" channel: %d\n\n", uc_key->channel);
3905a54baa7SJoseph Chen } else {
3915a54baa7SJoseph Chen const char *gpio_name =
3925a54baa7SJoseph Chen ofnode_get_name(ofnode_get_by_phandle(uc_key->gpios[0]));
3935a54baa7SJoseph Chen
3945a54baa7SJoseph Chen printf(" irq: %d\n", uc_key->irq);
3955a54baa7SJoseph Chen printf(" gpio[0]: %s\n", gpio_name);
3965a54baa7SJoseph Chen printf(" gpio[1]: %d\n\n", uc_key->gpios[1]);
3975a54baa7SJoseph Chen }
3985a54baa7SJoseph Chen #endif
3995a54baa7SJoseph Chen
4005a54baa7SJoseph Chen return 0;
4013fb84000SJoseph Chen }
4023fb84000SJoseph Chen
403b398a9a7SJoseph Chen UCLASS_DRIVER(key) = {
404b398a9a7SJoseph Chen .id = UCLASS_KEY,
405b398a9a7SJoseph Chen .name = "key",
4065a54baa7SJoseph Chen .post_probe = key_post_probe,
4075a54baa7SJoseph Chen .per_device_platdata_auto_alloc_size =
4085a54baa7SJoseph Chen sizeof(struct dm_key_uclass_platdata),
409b398a9a7SJoseph Chen };
410