-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HID: i2c-hid: Reorganize so ACPI and OF are separate modules
This patch rejiggers the i2c-hid code so that the OF (Open Firmware aka Device Tree) and ACPI support is separated out a bit. The OF and ACPI drivers are now separate modules that wrap the core module. Essentially, what we're doing here: * Make "power up" and "power down" a function that can be (optionally) implemented by a given user of the i2c-hid core. * The OF and ACPI modules are drivers on their own, so they implement probe / remove / suspend / resume / shutdown. The core code provides implementations that OF and ACPI can call into. We'll organize this so that we now have 3 modules: the old i2c-hid module becomes the "core" module and two new modules will depend on it, handling probing the specific device. As part of this work, we'll remove the i2c-hid "platform data" concept since it's not needed. Signed-off-by: Douglas Anderson <dianders@chromium.org> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
- Loading branch information
Douglas Anderson
authored and
Benjamin Tissoires
committed
Jan 18, 2021
1 parent
2bbe17a
commit b33752c
Showing
8 changed files
with
379 additions
and
261 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* | ||
* HID over I2C ACPI Subclass | ||
* | ||
* Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> | ||
* Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France | ||
* Copyright (c) 2012 Red Hat, Inc | ||
* | ||
* This code was forked out of the core code, which was partly based on | ||
* "USB HID support for Linux": | ||
* | ||
* Copyright (c) 1999 Andreas Gal | ||
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | ||
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | ||
* Copyright (c) 2007-2008 Oliver Neukum | ||
* Copyright (c) 2006-2010 Jiri Kosina | ||
* | ||
* This file is subject to the terms and conditions of the GNU General Public | ||
* License. See the file COPYING in the main directory of this archive for | ||
* more details. | ||
*/ | ||
|
||
#include <linux/acpi.h> | ||
#include <linux/device.h> | ||
#include <linux/i2c.h> | ||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/pm.h> | ||
|
||
#include "i2c-hid.h" | ||
|
||
struct i2c_hid_acpi { | ||
struct i2chid_ops ops; | ||
struct i2c_client *client; | ||
}; | ||
|
||
static const struct acpi_device_id i2c_hid_acpi_blacklist[] = { | ||
/* | ||
* The CHPN0001 ACPI device, which is used to describe the Chipone | ||
* ICN8505 controller, has a _CID of PNP0C50 but is not HID compatible. | ||
*/ | ||
{"CHPN0001", 0 }, | ||
{ }, | ||
}; | ||
|
||
static int i2c_hid_acpi_get_descriptor(struct i2c_client *client) | ||
{ | ||
static guid_t i2c_hid_guid = | ||
GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555, | ||
0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE); | ||
union acpi_object *obj; | ||
struct acpi_device *adev; | ||
acpi_handle handle; | ||
u16 hid_descriptor_address; | ||
|
||
handle = ACPI_HANDLE(&client->dev); | ||
if (!handle || acpi_bus_get_device(handle, &adev)) { | ||
dev_err(&client->dev, "Error could not get ACPI device\n"); | ||
return -ENODEV; | ||
} | ||
|
||
if (acpi_match_device_ids(adev, i2c_hid_acpi_blacklist) == 0) | ||
return -ENODEV; | ||
|
||
obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid, 1, 1, NULL, | ||
ACPI_TYPE_INTEGER); | ||
if (!obj) { | ||
dev_err(&client->dev, "Error _DSM call to get HID descriptor address failed\n"); | ||
return -ENODEV; | ||
} | ||
|
||
hid_descriptor_address = obj->integer.value; | ||
ACPI_FREE(obj); | ||
|
||
return hid_descriptor_address; | ||
} | ||
|
||
static void i2c_hid_acpi_shutdown_tail(struct i2chid_ops *ops) | ||
{ | ||
struct i2c_hid_acpi *ihid_acpi = | ||
container_of(ops, struct i2c_hid_acpi, ops); | ||
struct device *dev = &ihid_acpi->client->dev; | ||
acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D3_COLD); | ||
} | ||
|
||
static int i2c_hid_acpi_probe(struct i2c_client *client, | ||
const struct i2c_device_id *dev_id) | ||
{ | ||
struct device *dev = &client->dev; | ||
struct i2c_hid_acpi *ihid_acpi; | ||
struct acpi_device *adev; | ||
u16 hid_descriptor_address; | ||
int ret; | ||
|
||
ihid_acpi = devm_kzalloc(&client->dev, sizeof(*ihid_acpi), GFP_KERNEL); | ||
if (!ihid_acpi) | ||
return -ENOMEM; | ||
|
||
ihid_acpi->client = client; | ||
ihid_acpi->ops.shutdown_tail = i2c_hid_acpi_shutdown_tail; | ||
|
||
ret = i2c_hid_acpi_get_descriptor(client); | ||
if (ret < 0) | ||
return ret; | ||
hid_descriptor_address = ret; | ||
|
||
adev = ACPI_COMPANION(dev); | ||
if (adev) | ||
acpi_device_fix_up_power(adev); | ||
|
||
if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) { | ||
device_set_wakeup_capable(dev, true); | ||
device_set_wakeup_enable(dev, false); | ||
} | ||
|
||
return i2c_hid_core_probe(client, &ihid_acpi->ops, | ||
hid_descriptor_address); | ||
} | ||
|
||
static const struct acpi_device_id i2c_hid_acpi_match[] = { | ||
{"ACPI0C50", 0 }, | ||
{"PNP0C50", 0 }, | ||
{ }, | ||
}; | ||
MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match); | ||
|
||
static struct i2c_driver i2c_hid_acpi_driver = { | ||
.driver = { | ||
.name = "i2c_hid_acpi", | ||
.pm = &i2c_hid_core_pm, | ||
.probe_type = PROBE_PREFER_ASYNCHRONOUS, | ||
.acpi_match_table = ACPI_PTR(i2c_hid_acpi_match), | ||
}, | ||
|
||
.probe = i2c_hid_acpi_probe, | ||
.remove = i2c_hid_core_remove, | ||
.shutdown = i2c_hid_core_shutdown, | ||
}; | ||
|
||
module_i2c_driver(i2c_hid_acpi_driver); | ||
|
||
MODULE_DESCRIPTION("HID over I2C ACPI driver"); | ||
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); | ||
MODULE_LICENSE("GPL"); |
Oops, something went wrong.