]>
Commit | Line | Data |
---|---|---|
ce1cb0ee JL |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Azoteq IQS620A/621/622/624/625 Keys and Switches | |
4 | * | |
5 | * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com> | |
6 | */ | |
7 | ||
8 | #include <linux/device.h> | |
9 | #include <linux/input.h> | |
10 | #include <linux/kernel.h> | |
11 | #include <linux/mfd/iqs62x.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/notifier.h> | |
14 | #include <linux/platform_device.h> | |
15 | #include <linux/property.h> | |
16 | #include <linux/regmap.h> | |
17 | #include <linux/slab.h> | |
18 | ||
19 | enum { | |
20 | IQS62X_SW_HALL_N, | |
21 | IQS62X_SW_HALL_S, | |
22 | }; | |
23 | ||
24 | static const char * const iqs62x_switch_names[] = { | |
25 | [IQS62X_SW_HALL_N] = "hall-switch-north", | |
26 | [IQS62X_SW_HALL_S] = "hall-switch-south", | |
27 | }; | |
28 | ||
29 | struct iqs62x_switch_desc { | |
30 | enum iqs62x_event_flag flag; | |
31 | unsigned int code; | |
32 | bool enabled; | |
33 | }; | |
34 | ||
35 | struct iqs62x_keys_private { | |
36 | struct iqs62x_core *iqs62x; | |
37 | struct input_dev *input; | |
38 | struct notifier_block notifier; | |
39 | struct iqs62x_switch_desc switches[ARRAY_SIZE(iqs62x_switch_names)]; | |
40 | unsigned int keycode[IQS62X_NUM_KEYS]; | |
41 | unsigned int keycodemax; | |
42 | u8 interval; | |
43 | }; | |
44 | ||
45 | static int iqs62x_keys_parse_prop(struct platform_device *pdev, | |
46 | struct iqs62x_keys_private *iqs62x_keys) | |
47 | { | |
48 | struct fwnode_handle *child; | |
49 | unsigned int val; | |
50 | int ret, i; | |
51 | ||
52 | ret = device_property_count_u32(&pdev->dev, "linux,keycodes"); | |
53 | if (ret > IQS62X_NUM_KEYS) { | |
54 | dev_err(&pdev->dev, "Too many keycodes present\n"); | |
55 | return -EINVAL; | |
56 | } else if (ret < 0) { | |
57 | dev_err(&pdev->dev, "Failed to count keycodes: %d\n", ret); | |
58 | return ret; | |
59 | } | |
60 | iqs62x_keys->keycodemax = ret; | |
61 | ||
62 | ret = device_property_read_u32_array(&pdev->dev, "linux,keycodes", | |
63 | iqs62x_keys->keycode, | |
64 | iqs62x_keys->keycodemax); | |
65 | if (ret) { | |
66 | dev_err(&pdev->dev, "Failed to read keycodes: %d\n", ret); | |
67 | return ret; | |
68 | } | |
69 | ||
70 | for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) { | |
71 | child = device_get_named_child_node(&pdev->dev, | |
72 | iqs62x_switch_names[i]); | |
73 | if (!child) | |
74 | continue; | |
75 | ||
76 | ret = fwnode_property_read_u32(child, "linux,code", &val); | |
77 | if (ret) { | |
78 | dev_err(&pdev->dev, "Failed to read switch code: %d\n", | |
79 | ret); | |
80 | return ret; | |
81 | } | |
82 | iqs62x_keys->switches[i].code = val; | |
83 | iqs62x_keys->switches[i].enabled = true; | |
84 | ||
85 | if (fwnode_property_present(child, "azoteq,use-prox")) | |
86 | iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ? | |
87 | IQS62X_EVENT_HALL_N_P : | |
88 | IQS62X_EVENT_HALL_S_P); | |
89 | else | |
90 | iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ? | |
91 | IQS62X_EVENT_HALL_N_T : | |
92 | IQS62X_EVENT_HALL_S_T); | |
93 | } | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
98 | static int iqs62x_keys_init(struct iqs62x_keys_private *iqs62x_keys) | |
99 | { | |
100 | struct iqs62x_core *iqs62x = iqs62x_keys->iqs62x; | |
101 | enum iqs62x_event_flag flag; | |
102 | unsigned int event_reg, val; | |
103 | unsigned int event_mask = 0; | |
104 | int ret, i; | |
105 | ||
106 | switch (iqs62x->dev_desc->prod_num) { | |
107 | case IQS620_PROD_NUM: | |
108 | case IQS621_PROD_NUM: | |
109 | case IQS622_PROD_NUM: | |
110 | event_reg = IQS620_GLBL_EVENT_MASK; | |
111 | ||
112 | /* | |
113 | * Discreet button, hysteresis and SAR UI flags represent keys | |
114 | * and are unmasked if mapped to a valid keycode. | |
115 | */ | |
116 | for (i = 0; i < iqs62x_keys->keycodemax; i++) { | |
117 | if (iqs62x_keys->keycode[i] == KEY_RESERVED) | |
118 | continue; | |
119 | ||
120 | if (iqs62x_events[i].reg == IQS62X_EVENT_PROX) | |
121 | event_mask |= iqs62x->dev_desc->prox_mask; | |
122 | else if (iqs62x_events[i].reg == IQS62X_EVENT_HYST) | |
123 | event_mask |= (iqs62x->dev_desc->hyst_mask | | |
124 | iqs62x->dev_desc->sar_mask); | |
125 | } | |
126 | ||
127 | ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->hall_flags, | |
128 | &val); | |
129 | if (ret) | |
130 | return ret; | |
131 | ||
132 | /* | |
133 | * Hall UI flags represent switches and are unmasked if their | |
134 | * corresponding child nodes are present. | |
135 | */ | |
136 | for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) { | |
137 | if (!(iqs62x_keys->switches[i].enabled)) | |
138 | continue; | |
139 | ||
140 | flag = iqs62x_keys->switches[i].flag; | |
141 | ||
142 | if (iqs62x_events[flag].reg != IQS62X_EVENT_HALL) | |
143 | continue; | |
144 | ||
145 | event_mask |= iqs62x->dev_desc->hall_mask; | |
146 | ||
147 | input_report_switch(iqs62x_keys->input, | |
148 | iqs62x_keys->switches[i].code, | |
149 | (val & iqs62x_events[flag].mask) == | |
150 | iqs62x_events[flag].val); | |
151 | } | |
152 | ||
153 | input_sync(iqs62x_keys->input); | |
154 | break; | |
155 | ||
156 | case IQS624_PROD_NUM: | |
157 | event_reg = IQS624_HALL_UI; | |
158 | ||
159 | /* | |
160 | * Interval change events represent keys and are unmasked if | |
161 | * either wheel movement flag is mapped to a valid keycode. | |
162 | */ | |
163 | if (iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_UP] != KEY_RESERVED) | |
164 | event_mask |= IQS624_HALL_UI_INT_EVENT; | |
165 | ||
166 | if (iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_DN] != KEY_RESERVED) | |
167 | event_mask |= IQS624_HALL_UI_INT_EVENT; | |
168 | ||
169 | ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->interval, | |
170 | &val); | |
171 | if (ret) | |
172 | return ret; | |
173 | ||
174 | iqs62x_keys->interval = val; | |
175 | break; | |
176 | ||
177 | default: | |
178 | return 0; | |
179 | } | |
180 | ||
181 | return regmap_update_bits(iqs62x->regmap, event_reg, event_mask, 0); | |
182 | } | |
183 | ||
184 | static int iqs62x_keys_notifier(struct notifier_block *notifier, | |
185 | unsigned long event_flags, void *context) | |
186 | { | |
187 | struct iqs62x_event_data *event_data = context; | |
188 | struct iqs62x_keys_private *iqs62x_keys; | |
189 | int ret, i; | |
190 | ||
191 | iqs62x_keys = container_of(notifier, struct iqs62x_keys_private, | |
192 | notifier); | |
193 | ||
194 | if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) { | |
195 | ret = iqs62x_keys_init(iqs62x_keys); | |
196 | if (ret) { | |
197 | dev_err(iqs62x_keys->input->dev.parent, | |
198 | "Failed to re-initialize device: %d\n", ret); | |
199 | return NOTIFY_BAD; | |
200 | } | |
201 | ||
202 | return NOTIFY_OK; | |
203 | } | |
204 | ||
205 | for (i = 0; i < iqs62x_keys->keycodemax; i++) { | |
206 | if (iqs62x_events[i].reg == IQS62X_EVENT_WHEEL && | |
207 | event_data->interval == iqs62x_keys->interval) | |
208 | continue; | |
209 | ||
210 | input_report_key(iqs62x_keys->input, iqs62x_keys->keycode[i], | |
211 | event_flags & BIT(i)); | |
212 | } | |
213 | ||
214 | for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) | |
215 | if (iqs62x_keys->switches[i].enabled) | |
216 | input_report_switch(iqs62x_keys->input, | |
217 | iqs62x_keys->switches[i].code, | |
218 | event_flags & | |
219 | BIT(iqs62x_keys->switches[i].flag)); | |
220 | ||
221 | input_sync(iqs62x_keys->input); | |
222 | ||
223 | if (event_data->interval == iqs62x_keys->interval) | |
224 | return NOTIFY_OK; | |
225 | ||
226 | /* | |
227 | * Each frame contains at most one wheel event (up or down), in which | |
228 | * case a complementary release cycle is emulated. | |
229 | */ | |
230 | if (event_flags & BIT(IQS62X_EVENT_WHEEL_UP)) { | |
231 | input_report_key(iqs62x_keys->input, | |
232 | iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_UP], | |
233 | 0); | |
234 | input_sync(iqs62x_keys->input); | |
235 | } else if (event_flags & BIT(IQS62X_EVENT_WHEEL_DN)) { | |
236 | input_report_key(iqs62x_keys->input, | |
237 | iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_DN], | |
238 | 0); | |
239 | input_sync(iqs62x_keys->input); | |
240 | } | |
241 | ||
242 | iqs62x_keys->interval = event_data->interval; | |
243 | ||
244 | return NOTIFY_OK; | |
245 | } | |
246 | ||
247 | static int iqs62x_keys_probe(struct platform_device *pdev) | |
248 | { | |
249 | struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent); | |
250 | struct iqs62x_keys_private *iqs62x_keys; | |
251 | struct input_dev *input; | |
252 | int ret, i; | |
253 | ||
254 | iqs62x_keys = devm_kzalloc(&pdev->dev, sizeof(*iqs62x_keys), | |
255 | GFP_KERNEL); | |
256 | if (!iqs62x_keys) | |
257 | return -ENOMEM; | |
258 | ||
259 | platform_set_drvdata(pdev, iqs62x_keys); | |
260 | ||
261 | ret = iqs62x_keys_parse_prop(pdev, iqs62x_keys); | |
262 | if (ret) | |
263 | return ret; | |
264 | ||
265 | input = devm_input_allocate_device(&pdev->dev); | |
266 | if (!input) | |
267 | return -ENOMEM; | |
268 | ||
269 | input->keycodemax = iqs62x_keys->keycodemax; | |
270 | input->keycode = iqs62x_keys->keycode; | |
271 | input->keycodesize = sizeof(*iqs62x_keys->keycode); | |
272 | ||
273 | input->name = iqs62x->dev_desc->dev_name; | |
274 | input->id.bustype = BUS_I2C; | |
275 | ||
276 | for (i = 0; i < iqs62x_keys->keycodemax; i++) | |
277 | if (iqs62x_keys->keycode[i] != KEY_RESERVED) | |
278 | input_set_capability(input, EV_KEY, | |
279 | iqs62x_keys->keycode[i]); | |
280 | ||
281 | for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) | |
282 | if (iqs62x_keys->switches[i].enabled) | |
283 | input_set_capability(input, EV_SW, | |
284 | iqs62x_keys->switches[i].code); | |
285 | ||
286 | iqs62x_keys->iqs62x = iqs62x; | |
287 | iqs62x_keys->input = input; | |
288 | ||
289 | ret = iqs62x_keys_init(iqs62x_keys); | |
290 | if (ret) { | |
291 | dev_err(&pdev->dev, "Failed to initialize device: %d\n", ret); | |
292 | return ret; | |
293 | } | |
294 | ||
295 | ret = input_register_device(iqs62x_keys->input); | |
296 | if (ret) { | |
297 | dev_err(&pdev->dev, "Failed to register device: %d\n", ret); | |
298 | return ret; | |
299 | } | |
300 | ||
301 | iqs62x_keys->notifier.notifier_call = iqs62x_keys_notifier; | |
302 | ret = blocking_notifier_chain_register(&iqs62x_keys->iqs62x->nh, | |
303 | &iqs62x_keys->notifier); | |
304 | if (ret) | |
305 | dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret); | |
306 | ||
307 | return ret; | |
308 | } | |
309 | ||
310 | static int iqs62x_keys_remove(struct platform_device *pdev) | |
311 | { | |
312 | struct iqs62x_keys_private *iqs62x_keys = platform_get_drvdata(pdev); | |
313 | int ret; | |
314 | ||
315 | ret = blocking_notifier_chain_unregister(&iqs62x_keys->iqs62x->nh, | |
316 | &iqs62x_keys->notifier); | |
317 | if (ret) | |
318 | dev_err(&pdev->dev, "Failed to unregister notifier: %d\n", ret); | |
319 | ||
320 | return ret; | |
321 | } | |
322 | ||
323 | static struct platform_driver iqs62x_keys_platform_driver = { | |
324 | .driver = { | |
325 | .name = "iqs62x-keys", | |
326 | }, | |
327 | .probe = iqs62x_keys_probe, | |
328 | .remove = iqs62x_keys_remove, | |
329 | }; | |
330 | module_platform_driver(iqs62x_keys_platform_driver); | |
331 | ||
332 | MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); | |
333 | MODULE_DESCRIPTION("Azoteq IQS620A/621/622/624/625 Keys and Switches"); | |
334 | MODULE_LICENSE("GPL"); | |
335 | MODULE_ALIAS("platform:iqs62x-keys"); |