1
2
3
4
5
6
7
8
9
10
11
12#include <linux/input.h>
13#include <linux/input/touchscreen.h>
14#include <linux/iio/consumer.h>
15#include <linux/iio/iio.h>
16#include <linux/mod_devicetable.h>
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <linux/property.h>
20
21#define DRIVER_NAME "resistive-adc-touch"
22#define GRTS_DEFAULT_PRESSURE_MIN 50000
23#define GRTS_DEFAULT_PRESSURE_MAX 65535
24#define GRTS_MAX_POS_MASK GENMASK(11, 0)
25#define GRTS_MAX_CHANNELS 4
26
27enum grts_ch_type {
28 GRTS_CH_X,
29 GRTS_CH_Y,
30 GRTS_CH_PRESSURE,
31 GRTS_CH_Z1,
32 GRTS_CH_Z2,
33 GRTS_CH_MAX = GRTS_CH_Z2 + 1
34};
35
36
37
38
39
40
41
42
43
44
45
46
47struct grts_state {
48 u32 x_plate_ohms;
49 u32 pressure_min;
50 bool pressure;
51 struct iio_channel *iio_chans;
52 struct iio_cb_buffer *iio_cb;
53 struct input_dev *input;
54 struct touchscreen_properties prop;
55 u8 ch_map[GRTS_CH_MAX];
56};
57
58static int grts_cb(const void *data, void *private)
59{
60 const u16 *touch_info = data;
61 struct grts_state *st = private;
62 unsigned int x, y, press = 0;
63
64 x = touch_info[st->ch_map[GRTS_CH_X]];
65 y = touch_info[st->ch_map[GRTS_CH_Y]];
66
67 if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) {
68 press = touch_info[st->ch_map[GRTS_CH_PRESSURE]];
69 } else if (st->ch_map[GRTS_CH_Z1] < GRTS_MAX_CHANNELS) {
70 unsigned int z1 = touch_info[st->ch_map[GRTS_CH_Z1]];
71 unsigned int z2 = touch_info[st->ch_map[GRTS_CH_Z2]];
72 unsigned int Rt;
73
74 Rt = z2;
75 Rt -= z1;
76 Rt *= st->x_plate_ohms;
77 Rt = DIV_ROUND_CLOSEST(Rt, 16);
78 Rt *= x;
79 Rt /= z1;
80 Rt = DIV_ROUND_CLOSEST(Rt, 256);
81
82
83
84
85 if (Rt < GRTS_DEFAULT_PRESSURE_MAX)
86 press = GRTS_DEFAULT_PRESSURE_MAX - Rt;
87 }
88
89 if ((!x && !y) || (st->pressure && (press < st->pressure_min))) {
90
91 input_report_key(st->input, BTN_TOUCH, 0);
92 input_sync(st->input);
93 return 0;
94 }
95
96
97 touchscreen_report_pos(st->input, &st->prop, x, y, false);
98 if (st->pressure)
99 input_report_abs(st->input, ABS_PRESSURE, press);
100 input_report_key(st->input, BTN_TOUCH, 1);
101 input_sync(st->input);
102
103 return 0;
104}
105
106static int grts_open(struct input_dev *dev)
107{
108 int error;
109 struct grts_state *st = input_get_drvdata(dev);
110
111 error = iio_channel_start_all_cb(st->iio_cb);
112 if (error) {
113 dev_err(dev->dev.parent, "failed to start callback buffer.\n");
114 return error;
115 }
116 return 0;
117}
118
119static void grts_close(struct input_dev *dev)
120{
121 struct grts_state *st = input_get_drvdata(dev);
122
123 iio_channel_stop_all_cb(st->iio_cb);
124}
125
126static void grts_disable(void *data)
127{
128 iio_channel_release_all_cb(data);
129}
130
131static int grts_map_channel(struct grts_state *st, struct device *dev,
132 enum grts_ch_type type, const char *name,
133 bool optional)
134{
135 int idx;
136
137 idx = device_property_match_string(dev, "io-channel-names", name);
138 if (idx < 0) {
139 if (!optional)
140 return idx;
141 idx = GRTS_MAX_CHANNELS;
142 } else if (idx >= GRTS_MAX_CHANNELS) {
143 return -EOVERFLOW;
144 }
145
146 st->ch_map[type] = idx;
147 return 0;
148}
149
150static int grts_get_properties(struct grts_state *st, struct device *dev)
151{
152 int error;
153
154 error = grts_map_channel(st, dev, GRTS_CH_X, "x", false);
155 if (error)
156 return error;
157
158 error = grts_map_channel(st, dev, GRTS_CH_Y, "y", false);
159 if (error)
160 return error;
161
162
163 error = grts_map_channel(st, dev, GRTS_CH_PRESSURE, "pressure", true);
164 if (error)
165 return error;
166
167 if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) {
168 st->pressure = true;
169 return 0;
170 }
171
172
173 error = grts_map_channel(st, dev, GRTS_CH_Z1, "z1", true);
174 if (error)
175 return error;
176
177 if (st->ch_map[GRTS_CH_Z1] >= GRTS_MAX_CHANNELS)
178 return 0;
179
180
181 error = grts_map_channel(st, dev, GRTS_CH_Z2, "z2", true);
182 if (error)
183 return error;
184
185 error = device_property_read_u32(dev,
186 "touchscreen-x-plate-ohms",
187 &st->x_plate_ohms);
188 if (error) {
189 dev_err(dev, "can't get touchscreen-x-plate-ohms property\n");
190 return error;
191 }
192
193 st->pressure = true;
194 return 0;
195}
196
197static int grts_probe(struct platform_device *pdev)
198{
199 struct grts_state *st;
200 struct input_dev *input;
201 struct device *dev = &pdev->dev;
202 int error;
203
204 st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL);
205 if (!st)
206 return -ENOMEM;
207
208
209 st->iio_chans = devm_iio_channel_get_all(dev);
210 if (IS_ERR(st->iio_chans)) {
211 error = PTR_ERR(st->iio_chans);
212 if (error != -EPROBE_DEFER)
213 dev_err(dev, "can't get iio channels.\n");
214 return error;
215 }
216
217 if (!device_property_present(dev, "io-channel-names"))
218 return -ENODEV;
219
220 error = grts_get_properties(st, dev);
221 if (error) {
222 dev_err(dev, "Failed to parse properties\n");
223 return error;
224 }
225
226 if (st->pressure) {
227 error = device_property_read_u32(dev,
228 "touchscreen-min-pressure",
229 &st->pressure_min);
230 if (error) {
231 dev_dbg(dev, "can't get touchscreen-min-pressure property.\n");
232 st->pressure_min = GRTS_DEFAULT_PRESSURE_MIN;
233 }
234 }
235
236 input = devm_input_allocate_device(dev);
237 if (!input) {
238 dev_err(dev, "failed to allocate input device.\n");
239 return -ENOMEM;
240 }
241
242 input->name = DRIVER_NAME;
243 input->id.bustype = BUS_HOST;
244 input->open = grts_open;
245 input->close = grts_close;
246
247 input_set_abs_params(input, ABS_X, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
248 input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
249 if (st->pressure)
250 input_set_abs_params(input, ABS_PRESSURE, st->pressure_min,
251 GRTS_DEFAULT_PRESSURE_MAX, 0, 0);
252
253 input_set_capability(input, EV_KEY, BTN_TOUCH);
254
255
256 touchscreen_parse_properties(input, false, &st->prop);
257
258 st->input = input;
259 input_set_drvdata(input, st);
260
261 error = input_register_device(input);
262 if (error) {
263 dev_err(dev, "failed to register input device.");
264 return error;
265 }
266
267 st->iio_cb = iio_channel_get_all_cb(dev, grts_cb, st);
268 if (IS_ERR(st->iio_cb)) {
269 dev_err(dev, "failed to allocate callback buffer.\n");
270 return PTR_ERR(st->iio_cb);
271 }
272
273 error = devm_add_action_or_reset(dev, grts_disable, st->iio_cb);
274 if (error) {
275 dev_err(dev, "failed to add disable action.\n");
276 return error;
277 }
278
279 return 0;
280}
281
282static const struct of_device_id grts_of_match[] = {
283 {
284 .compatible = "resistive-adc-touch",
285 }, {
286
287 },
288};
289
290MODULE_DEVICE_TABLE(of, grts_of_match);
291
292static struct platform_driver grts_driver = {
293 .probe = grts_probe,
294 .driver = {
295 .name = DRIVER_NAME,
296 .of_match_table = grts_of_match,
297 },
298};
299
300module_platform_driver(grts_driver);
301
302MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
303MODULE_DESCRIPTION("Generic ADC Resistive Touch Driver");
304MODULE_LICENSE("GPL v2");
305