1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2021 Samsung Electronics Co., Ltd.
4  *		http://www.samsung.com
5  * Author: Marek Szyprowski <m.szyprowski@samsung.com>
6  */
7 
8 #include <common.h>
9 #include <adc.h>
10 #include <button.h>
11 #include <log.h>
12 #include <dm.h>
13 #include <dm/lists.h>
14 #include <dm/of_access.h>
15 #include <dm/uclass-internal.h>
16 
17 /**
18  * struct button_adc_priv - private data for button-adc driver.
19  *
20  * @adc: Analog to Digital Converter device to which button is connected.
21  * @channel: channel of the ADC device to probe the button state.
22  * @min: minimal uV value to consider button as pressed.
23  * @max: maximal uV value to consider button as pressed.
24  */
25 struct button_adc_priv {
26 	struct udevice *adc;
27 	int channel;
28 	int min;
29 	int max;
30 };
31 
button_adc_get_state(struct udevice * dev)32 static enum button_state_t button_adc_get_state(struct udevice *dev)
33 {
34 	struct button_adc_priv *priv = dev_get_priv(dev);
35 	unsigned int val;
36 	int ret, uV;
37 
38 	ret = adc_start_channel(priv->adc, priv->channel);
39 	if (ret)
40 		return ret;
41 
42 	ret = adc_channel_data(priv->adc, priv->channel, &val);
43 	if (ret)
44 		return ret;
45 
46 	ret = adc_raw_to_uV(priv->adc, val, &uV);
47 	if (ret)
48 		return ret;
49 
50 	return (uV >= priv->min && uV < priv->max) ? BUTTON_ON : BUTTON_OFF;
51 }
52 
button_adc_of_to_plat(struct udevice * dev)53 static int button_adc_of_to_plat(struct udevice *dev)
54 {
55 	struct button_uc_plat *uc_plat = dev_get_uclass_plat(dev);
56 	struct button_adc_priv *priv = dev_get_priv(dev);
57 	struct ofnode_phandle_args args;
58 	u32 threshold, up_threshold, t;
59 	ofnode node;
60 	int ret;
61 
62 	/* Ignore the top-level button node */
63 	if (!uc_plat->label)
64 		return 0;
65 
66 	ret = dev_read_phandle_with_args(dev->parent, "io-channels",
67 					 "#io-channel-cells", 0, 0, &args);
68 	if (ret)
69 		return ret;
70 
71 	ret = uclass_get_device_by_ofnode(UCLASS_ADC, args.node, &priv->adc);
72 	if (ret)
73 		return ret;
74 
75 	ret = ofnode_read_u32(dev_ofnode(dev->parent),
76 			      "keyup-threshold-microvolt", &up_threshold);
77 	if (ret)
78 		return ret;
79 
80 	ret = ofnode_read_u32(dev_ofnode(dev), "press-threshold-microvolt",
81 			      &threshold);
82 	if (ret)
83 		return ret;
84 
85 	dev_for_each_subnode(node, dev->parent) {
86 		ret = ofnode_read_u32(node, "press-threshold-microvolt", &t);
87 		if (ret)
88 			return ret;
89 
90 		if (t > threshold)
91 			up_threshold = t;
92 	}
93 
94 	priv->channel = args.args[0];
95 	priv->min = threshold;
96 	priv->max = up_threshold;
97 
98 	return ret;
99 }
100 
button_adc_bind(struct udevice * parent)101 static int button_adc_bind(struct udevice *parent)
102 {
103 	struct udevice *dev;
104 	ofnode node;
105 	int ret;
106 
107 	dev_for_each_subnode(node, parent) {
108 		struct button_uc_plat *uc_plat;
109 		const char *label;
110 
111 		label = ofnode_read_string(node, "label");
112 		if (!label) {
113 			debug("%s: node %s has no label\n", __func__,
114 			      ofnode_get_name(node));
115 			return -EINVAL;
116 		}
117 		ret = device_bind_driver_to_node(parent, "button_adc",
118 						 ofnode_get_name(node),
119 						 node, &dev);
120 		if (ret)
121 			return ret;
122 		uc_plat = dev_get_uclass_plat(dev);
123 		uc_plat->label = label;
124 	}
125 
126 	return 0;
127 }
128 
129 static const struct button_ops button_adc_ops = {
130 	.get_state	= button_adc_get_state,
131 };
132 
133 static const struct udevice_id button_adc_ids[] = {
134 	{ .compatible = "adc-keys" },
135 	{ }
136 };
137 
138 U_BOOT_DRIVER(button_adc) = {
139 	.name		= "button_adc",
140 	.id		= UCLASS_BUTTON,
141 	.of_match	= button_adc_ids,
142 	.ops		= &button_adc_ops,
143 	.priv_auto	= sizeof(struct button_adc_priv),
144 	.bind		= button_adc_bind,
145 	.of_to_plat	= button_adc_of_to_plat,
146 };
147