xref: /openbmc/linux/drivers/platform/chrome/chromeos_tbmc.c (revision ea47eed33a3fe3d919e6e3cf4e4eb5507b817188)
1 // SPDX-License-Identifier: GPL-2.0+
2 // Driver to detect Tablet Mode for ChromeOS convertible.
3 //
4 // Copyright (C) 2017 Google, Inc.
5 // Author: Gwendal Grignou <gwendal@chromium.org>
6 
7 #include <linux/acpi.h>
8 #include <linux/input.h>
9 #include <linux/io.h>
10 #include <linux/module.h>
11 #include <linux/printk.h>
12 
13 #define DRV_NAME "chromeos_tbmc"
14 #define ACPI_DRV_NAME "GOOG0006"
15 
16 static int chromeos_tbmc_query_switch(struct acpi_device *adev,
17 				     struct input_dev *idev)
18 {
19 	unsigned long long state;
20 	acpi_status status;
21 
22 	status = acpi_evaluate_integer(adev->handle, "TBMC", NULL, &state);
23 	if (ACPI_FAILURE(status))
24 		return -ENODEV;
25 
26 	/* input layer checks if event is redundant */
27 	input_report_switch(idev, SW_TABLET_MODE, state);
28 	input_sync(idev);
29 
30 	return 0;
31 }
32 
33 static __maybe_unused int chromeos_tbmc_resume(struct device *dev)
34 {
35 	struct acpi_device *adev = to_acpi_device(dev);
36 
37 	return chromeos_tbmc_query_switch(adev, adev->driver_data);
38 }
39 
40 static void chromeos_tbmc_notify(struct acpi_device *adev, u32 event)
41 {
42 	switch (event) {
43 	case 0x80:
44 		chromeos_tbmc_query_switch(adev, adev->driver_data);
45 		break;
46 	default:
47 		dev_err(&adev->dev, "Unexpected event: 0x%08X\n", event);
48 	}
49 }
50 
51 static int chromeos_tbmc_open(struct input_dev *idev)
52 {
53 	struct acpi_device *adev = input_get_drvdata(idev);
54 
55 	return chromeos_tbmc_query_switch(adev, idev);
56 }
57 
58 static int chromeos_tbmc_add(struct acpi_device *adev)
59 {
60 	struct input_dev *idev;
61 	struct device *dev = &adev->dev;
62 	int ret;
63 
64 	idev = devm_input_allocate_device(dev);
65 	if (!idev)
66 		return -ENOMEM;
67 
68 	idev->name = "Tablet Mode Switch";
69 	idev->phys = acpi_device_hid(adev);
70 
71 	idev->id.bustype = BUS_HOST;
72 	idev->id.version = 1;
73 	idev->id.product = 0;
74 	idev->open = chromeos_tbmc_open;
75 
76 	input_set_drvdata(idev, adev);
77 	adev->driver_data = idev;
78 
79 	input_set_capability(idev, EV_SW, SW_TABLET_MODE);
80 	ret = input_register_device(idev);
81 	if (ret) {
82 		dev_err(dev, "cannot register input device\n");
83 		return ret;
84 	}
85 	return 0;
86 }
87 
88 static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = {
89 	{ ACPI_DRV_NAME, 0 },
90 	{ }
91 };
92 MODULE_DEVICE_TABLE(acpi, chromeos_tbmc_acpi_device_ids);
93 
94 static const SIMPLE_DEV_PM_OPS(chromeos_tbmc_pm_ops, NULL,
95 		chromeos_tbmc_resume);
96 
97 static struct acpi_driver chromeos_tbmc_driver = {
98 	.name = DRV_NAME,
99 	.class = DRV_NAME,
100 	.ids = chromeos_tbmc_acpi_device_ids,
101 	.ops = {
102 		.add = chromeos_tbmc_add,
103 		.notify = chromeos_tbmc_notify,
104 	},
105 	.drv.pm = &chromeos_tbmc_pm_ops,
106 };
107 
108 module_acpi_driver(chromeos_tbmc_driver);
109 
110 MODULE_LICENSE("GPL v2");
111 MODULE_DESCRIPTION("ChromeOS ACPI tablet switch driver");
112