1// SPDX-License-Identifier: GPL-2.0+
2/*
3 *  HID driver for Google Hammer device.
4 *
5 *  Copyright (c) 2017 Google Inc.
6 *  Author: Wei-Ning Huang <wnhuang@google.com>
7 */
8
9/*
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 */
15
16#include <linux/acpi.h>
17#include <linux/hid.h>
18#include <linux/leds.h>
19#include <linux/module.h>
20#include <linux/platform_data/cros_ec_commands.h>
21#include <linux/platform_data/cros_ec_proto.h>
22#include <linux/platform_device.h>
23#include <linux/pm_wakeup.h>
24#include <asm/unaligned.h>
25
26#include "hid-ids.h"
27
28/*
29 * C(hrome)B(ase)A(ttached)S(witch) - switch exported by Chrome EC and reporting
30 * state of the "Whiskers" base - attached or detached. Whiskers USB device also
31 * reports position of the keyboard - folded or not. Combining base state and
32 * position allows us to generate proper "Tablet mode" events.
33 */
34struct cbas_ec {
35	struct device *dev;	/* The platform device (EC) */
36	struct input_dev *input;
37	bool base_present;
38	bool base_folded;
39	struct notifier_block notifier;
40};
41
42static struct cbas_ec cbas_ec;
43static DEFINE_SPINLOCK(cbas_ec_lock);
44static DEFINE_MUTEX(cbas_ec_reglock);
45
46static bool cbas_parse_base_state(const void *data)
47{
48	u32 switches = get_unaligned_le32(data);
49
50	return !!(switches & BIT(EC_MKBP_BASE_ATTACHED));
51}
52
53static int cbas_ec_query_base(struct cros_ec_device *ec_dev, bool get_state,
54				  bool *state)
55{
56	struct ec_params_mkbp_info *params;
57	struct cros_ec_command *msg;
58	int ret;
59
60	msg = kzalloc(sizeof(*msg) + max(sizeof(u32), sizeof(*params)),
61		      GFP_KERNEL);
62	if (!msg)
63		return -ENOMEM;
64
65	msg->command = EC_CMD_MKBP_INFO;
66	msg->version = 1;
67	msg->outsize = sizeof(*params);
68	msg->insize = sizeof(u32);
69	params = (struct ec_params_mkbp_info *)msg->data;
70	params->info_type = get_state ?
71		EC_MKBP_INFO_CURRENT : EC_MKBP_INFO_SUPPORTED;
72	params->event_type = EC_MKBP_EVENT_SWITCH;
73
74	ret = cros_ec_cmd_xfer_status(ec_dev, msg);
75	if (ret >= 0) {
76		if (ret != sizeof(u32)) {
77			dev_warn(ec_dev->dev, "wrong result size: %d != %zu\n",
78				 ret, sizeof(u32));
79			ret = -EPROTO;
80		} else {
81			*state = cbas_parse_base_state(msg->data);
82			ret = 0;
83		}
84	}
85
86	kfree(msg);
87
88	return ret;
89}
90
91static int cbas_ec_notify(struct notifier_block *nb,
92			      unsigned long queued_during_suspend,
93			      void *_notify)
94{
95	struct cros_ec_device *ec = _notify;
96	unsigned long flags;
97	bool base_present;
98
99	if (ec->event_data.event_type == EC_MKBP_EVENT_SWITCH) {
100		base_present = cbas_parse_base_state(
101					&ec->event_data.data.switches);
102		dev_dbg(cbas_ec.dev,
103			"%s: base: %d\n", __func__, base_present);
104
105		if (device_may_wakeup(cbas_ec.dev) ||
106		    !queued_during_suspend) {
107
108			pm_wakeup_event(cbas_ec.dev, 0);
109
110			spin_lock_irqsave(&cbas_ec_lock, flags);
111
112			/*
113			 * While input layer dedupes the events, we do not want
114			 * to disrupt the state reported by the base by
115			 * overriding it with state reported by the LID. Only
116			 * report changes, as we assume that on attach the base
117			 * is not folded.
118			 */
119			if (base_present != cbas_ec.base_present) {
120				input_report_switch(cbas_ec.input,
121						    SW_TABLET_MODE,
122						    !base_present);
123				input_sync(cbas_ec.input);
124				cbas_ec.base_present = base_present;
125			}
126
127			spin_unlock_irqrestore(&cbas_ec_lock, flags);
128		}
129	}
130
131	return NOTIFY_OK;
132}
133
134static __maybe_unused int cbas_ec_resume(struct device *dev)
135{
136	struct cros_ec_device *ec = dev_get_drvdata(dev->parent);
137	bool base_present;
138	int error;
139
140	error = cbas_ec_query_base(ec, true, &base_present);
141	if (error) {
142		dev_warn(dev, "failed to fetch base state on resume: %d\n",
143			 error);
144	} else {
145		spin_lock_irq(&cbas_ec_lock);
146
147		cbas_ec.base_present = base_present;
148
149		/*
150		 * Only report if base is disconnected. If base is connected,
151		 * it will resend its state on resume, and we'll update it
152		 * in hammer_event().
153		 */
154		if (!cbas_ec.base_present) {
155			input_report_switch(cbas_ec.input, SW_TABLET_MODE, 1);
156			input_sync(cbas_ec.input);
157		}
158
159		spin_unlock_irq(&cbas_ec_lock);
160	}
161
162	return 0;
163}
164
165static SIMPLE_DEV_PM_OPS(cbas_ec_pm_ops, NULL, cbas_ec_resume);
166
167static void cbas_ec_set_input(struct input_dev *input)
168{
169	/* Take the lock so hammer_event() does not race with us here */
170	spin_lock_irq(&cbas_ec_lock);
171	cbas_ec.input = input;
172	spin_unlock_irq(&cbas_ec_lock);
173}
174
175static int __cbas_ec_probe(struct platform_device *pdev)
176{
177	struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
178	struct input_dev *input;
179	bool base_supported;
180	int error;
181
182	error = cbas_ec_query_base(ec, false, &base_supported);
183	if (error)
184		return error;
185
186	if (!base_supported)
187		return -ENXIO;
188
189	input = devm_input_allocate_device(&pdev->dev);
190	if (!input)
191		return -ENOMEM;
192
193	input->name = "Whiskers Tablet Mode Switch";
194	input->id.bustype = BUS_HOST;
195
196	input_set_capability(input, EV_SW, SW_TABLET_MODE);
197
198	error = input_register_device(input);
199	if (error) {
200		dev_err(&pdev->dev, "cannot register input device: %d\n",
201			error);
202		return error;
203	}
204
205	/* Seed the state */
206	error = cbas_ec_query_base(ec, true, &cbas_ec.base_present);
207	if (error) {
208		dev_err(&pdev->dev, "cannot query base state: %d\n", error);
209		return error;
210	}
211
212	if (!cbas_ec.base_present)
213		cbas_ec.base_folded = false;
214
215	dev_dbg(&pdev->dev, "%s: base: %d, folded: %d\n", __func__,
216		cbas_ec.base_present, cbas_ec.base_folded);
217
218	input_report_switch(input, SW_TABLET_MODE,
219			    !cbas_ec.base_present || cbas_ec.base_folded);
220
221	cbas_ec_set_input(input);
222
223	cbas_ec.dev = &pdev->dev;
224	cbas_ec.notifier.notifier_call = cbas_ec_notify;
225	error = blocking_notifier_chain_register(&ec->event_notifier,
226						 &cbas_ec.notifier);
227	if (error) {
228		dev_err(&pdev->dev, "cannot register notifier: %d\n", error);
229		cbas_ec_set_input(NULL);
230		return error;
231	}
232
233	device_init_wakeup(&pdev->dev, true);
234	return 0;
235}
236
237static int cbas_ec_probe(struct platform_device *pdev)
238{
239	int retval;
240
241	mutex_lock(&cbas_ec_reglock);
242
243	if (cbas_ec.input) {
244		retval = -EBUSY;
245		goto out;
246	}
247
248	retval = __cbas_ec_probe(pdev);
249
250out:
251	mutex_unlock(&cbas_ec_reglock);
252	return retval;
253}
254
255static int cbas_ec_remove(struct platform_device *pdev)
256{
257	struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
258
259	mutex_lock(&cbas_ec_reglock);
260
261	blocking_notifier_chain_unregister(&ec->event_notifier,
262					   &cbas_ec.notifier);
263	cbas_ec_set_input(NULL);
264
265	mutex_unlock(&cbas_ec_reglock);
266	return 0;
267}
268
269static const struct acpi_device_id cbas_ec_acpi_ids[] = {
270	{ "GOOG000B", 0 },
271	{ }
272};
273MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids);
274
275static struct platform_driver cbas_ec_driver = {
276	.probe = cbas_ec_probe,
277	.remove = cbas_ec_remove,
278	.driver = {
279		.name = "cbas_ec",
280		.acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids),
281		.pm = &cbas_ec_pm_ops,
282	},
283};
284
285#define MAX_BRIGHTNESS 100
286
287struct hammer_kbd_leds {
288	struct led_classdev cdev;
289	struct hid_device *hdev;
290	u8 buf[2] ____cacheline_aligned;
291};
292
293static int hammer_kbd_brightness_set_blocking(struct led_classdev *cdev,
294		enum led_brightness br)
295{
296	struct hammer_kbd_leds *led = container_of(cdev,
297						   struct hammer_kbd_leds,
298						   cdev);
299	int ret;
300
301	led->buf[0] = 0;
302	led->buf[1] = br;
303
304	/*
305	 * Request USB HID device to be in Full On mode, so that sending
306	 * hardware output report and hardware raw request won't fail.
307	 */
308	ret = hid_hw_power(led->hdev, PM_HINT_FULLON);
309	if (ret < 0) {
310		hid_err(led->hdev, "failed: device not resumed %d\n", ret);
311		return ret;
312	}
313
314	ret = hid_hw_output_report(led->hdev, led->buf, sizeof(led->buf));
315	if (ret == -ENOSYS)
316		ret = hid_hw_raw_request(led->hdev, 0, led->buf,
317					 sizeof(led->buf),
318					 HID_OUTPUT_REPORT,
319					 HID_REQ_SET_REPORT);
320	if (ret < 0)
321		hid_err(led->hdev, "failed to set keyboard backlight: %d\n",
322			ret);
323
324	/* Request USB HID device back to Normal Mode. */
325	hid_hw_power(led->hdev, PM_HINT_NORMAL);
326
327	return ret;
328}
329
330static int hammer_register_leds(struct hid_device *hdev)
331{
332	struct hammer_kbd_leds *kbd_backlight;
333	int error;
334
335	kbd_backlight = kzalloc(sizeof(*kbd_backlight), GFP_KERNEL);
336	if (!kbd_backlight)
337		return -ENOMEM;
338
339	kbd_backlight->hdev = hdev;
340	kbd_backlight->cdev.name = "hammer::kbd_backlight";
341	kbd_backlight->cdev.max_brightness = MAX_BRIGHTNESS;
342	kbd_backlight->cdev.brightness_set_blocking =
343		hammer_kbd_brightness_set_blocking;
344	kbd_backlight->cdev.flags = LED_HW_PLUGGABLE;
345
346	/* Set backlight to 0% initially. */
347	hammer_kbd_brightness_set_blocking(&kbd_backlight->cdev, 0);
348
349	error = led_classdev_register(&hdev->dev, &kbd_backlight->cdev);
350	if (error)
351		goto err_free_mem;
352
353	hid_set_drvdata(hdev, kbd_backlight);
354	return 0;
355
356err_free_mem:
357	kfree(kbd_backlight);
358	return error;
359}
360
361static void hammer_unregister_leds(struct hid_device *hdev)
362{
363	struct hammer_kbd_leds *kbd_backlight = hid_get_drvdata(hdev);
364
365	if (kbd_backlight) {
366		led_classdev_unregister(&kbd_backlight->cdev);
367		kfree(kbd_backlight);
368	}
369}
370
371#define HID_UP_GOOGLEVENDOR	0xffd10000
372#define HID_VD_KBD_FOLDED	0x00000019
373#define HID_USAGE_KBD_FOLDED	(HID_UP_GOOGLEVENDOR | HID_VD_KBD_FOLDED)
374
375/* HID usage for keyboard backlight (Alphanumeric display brightness) */
376#define HID_AD_BRIGHTNESS	0x00140046
377
378static int hammer_input_mapping(struct hid_device *hdev, struct hid_input *hi,
379				struct hid_field *field,
380				struct hid_usage *usage,
381				unsigned long **bit, int *max)
382{
383	if (usage->hid == HID_USAGE_KBD_FOLDED) {
384		/*
385		 * We do not want to have this usage mapped as it will get
386		 * mixed in with "base attached" signal and delivered over
387		 * separate input device for tablet switch mode.
388		 */
389		return -1;
390	}
391
392	return 0;
393}
394
395static int hammer_event(struct hid_device *hid, struct hid_field *field,
396			struct hid_usage *usage, __s32 value)
397{
398	unsigned long flags;
399
400	if (usage->hid == HID_USAGE_KBD_FOLDED) {
401		spin_lock_irqsave(&cbas_ec_lock, flags);
402
403		/*
404		 * If we are getting events from Whiskers that means that it
405		 * is attached to the lid.
406		 */
407		cbas_ec.base_present = true;
408		cbas_ec.base_folded = value;
409		hid_dbg(hid, "%s: base: %d, folded: %d\n", __func__,
410			cbas_ec.base_present, cbas_ec.base_folded);
411
412		if (cbas_ec.input) {
413			input_report_switch(cbas_ec.input,
414					    SW_TABLET_MODE, value);
415			input_sync(cbas_ec.input);
416		}
417
418		spin_unlock_irqrestore(&cbas_ec_lock, flags);
419		return 1; /* We handled this event */
420	}
421
422	return 0;
423}
424
425static bool hammer_has_usage(struct hid_device *hdev, unsigned int report_type,
426			unsigned application, unsigned usage)
427{
428	struct hid_report_enum *re = &hdev->report_enum[report_type];
429	struct hid_report *report;
430	int i, j;
431
432	list_for_each_entry(report, &re->report_list, list) {
433		if (report->application != application)
434			continue;
435
436		for (i = 0; i < report->maxfield; i++) {
437			struct hid_field *field = report->field[i];
438
439			for (j = 0; j < field->maxusage; j++)
440				if (field->usage[j].hid == usage)
441					return true;
442		}
443	}
444
445	return false;
446}
447
448static bool hammer_has_folded_event(struct hid_device *hdev)
449{
450	return hammer_has_usage(hdev, HID_INPUT_REPORT,
451				HID_GD_KEYBOARD, HID_USAGE_KBD_FOLDED);
452}
453
454static bool hammer_has_backlight_control(struct hid_device *hdev)
455{
456	return hammer_has_usage(hdev, HID_OUTPUT_REPORT,
457				HID_GD_KEYBOARD, HID_AD_BRIGHTNESS);
458}
459
460static int hammer_probe(struct hid_device *hdev,
461			const struct hid_device_id *id)
462{
463	int error;
464
465	error = hid_parse(hdev);
466	if (error)
467		return error;
468
469	error = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
470	if (error)
471		return error;
472
473	/*
474	 * We always want to poll for, and handle tablet mode events from
475	 * devices that have folded usage, even when nobody has opened the input
476	 * device. This also prevents the hid core from dropping early tablet
477	 * mode events from the device.
478	 */
479	if (hammer_has_folded_event(hdev)) {
480		hdev->quirks |= HID_QUIRK_ALWAYS_POLL;
481		error = hid_hw_open(hdev);
482		if (error)
483			return error;
484	}
485
486	if (hammer_has_backlight_control(hdev)) {
487		error = hammer_register_leds(hdev);
488		if (error)
489			hid_warn(hdev,
490				"Failed to register keyboard backlight: %d\n",
491				error);
492	}
493
494	return 0;
495}
496
497static void hammer_remove(struct hid_device *hdev)
498{
499	unsigned long flags;
500
501	if (hammer_has_folded_event(hdev)) {
502		hid_hw_close(hdev);
503
504		/*
505		 * If we are disconnecting then most likely Whiskers is
506		 * being removed. Even if it is not removed, without proper
507		 * keyboard we should not stay in clamshell mode.
508		 *
509		 * The reason for doing it here and not waiting for signal
510		 * from EC, is that on some devices there are high leakage
511		 * on Whiskers pins and we do not detect disconnect reliably,
512		 * resulting in devices being stuck in clamshell mode.
513		 */
514		spin_lock_irqsave(&cbas_ec_lock, flags);
515		if (cbas_ec.input && cbas_ec.base_present) {
516			input_report_switch(cbas_ec.input, SW_TABLET_MODE, 1);
517			input_sync(cbas_ec.input);
518		}
519		cbas_ec.base_present = false;
520		spin_unlock_irqrestore(&cbas_ec_lock, flags);
521	}
522
523	hammer_unregister_leds(hdev);
524
525	hid_hw_stop(hdev);
526}
527
528static const struct hid_device_id hammer_devices[] = {
529	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
530		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_DON) },
531	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
532		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_EEL) },
533	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
534		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) },
535	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
536		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_JEWEL) },
537	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
538		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MAGNEMITE) },
539	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
540		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MASTERBALL) },
541	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
542		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MOONBALL) },
543	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
544		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STAFF) },
545	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
546		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_WAND) },
547	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
548		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_WHISKERS) },
549	{ }
550};
551MODULE_DEVICE_TABLE(hid, hammer_devices);
552
553static struct hid_driver hammer_driver = {
554	.name = "hammer",
555	.id_table = hammer_devices,
556	.probe = hammer_probe,
557	.remove = hammer_remove,
558	.input_mapping = hammer_input_mapping,
559	.event = hammer_event,
560};
561
562static int __init hammer_init(void)
563{
564	int error;
565
566	error = platform_driver_register(&cbas_ec_driver);
567	if (error)
568		return error;
569
570	error = hid_register_driver(&hammer_driver);
571	if (error) {
572		platform_driver_unregister(&cbas_ec_driver);
573		return error;
574	}
575
576	return 0;
577}
578module_init(hammer_init);
579
580static void __exit hammer_exit(void)
581{
582	hid_unregister_driver(&hammer_driver);
583	platform_driver_unregister(&cbas_ec_driver);
584}
585module_exit(hammer_exit);
586
587MODULE_LICENSE("GPL");
588