From patchwork Thu Nov 12 00:41:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11898755 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 414EA1391 for ; Thu, 12 Nov 2020 01:34:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0AE5B20809 for ; Thu, 12 Nov 2020 01:34:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="k0hc7c94" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728120AbgKLBeH (ORCPT ); Wed, 11 Nov 2020 20:34:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44358 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728124AbgKLAmj (ORCPT ); Wed, 11 Nov 2020 19:42:39 -0500 Received: from mail-pf1-x430.google.com (mail-pf1-x430.google.com [IPv6:2607:f8b0:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 794C3C061A47 for ; Wed, 11 Nov 2020 16:41:41 -0800 (PST) Received: by mail-pf1-x430.google.com with SMTP id z3so2868843pfb.10 for ; Wed, 11 Nov 2020 16:41:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=qQy7AVFfkbCRSsX49etjlHfxC49CU8vL33FvFW19nVQ=; b=k0hc7c94ZTwKZ6Q+AGybD1HSk0WyuNGUX9RyLnc/taZ6DETE32CXerZBa3PJD71bfM QxWfK3KfwelrJow9qWQR4rc21IjpzVOgfr+X5ebGoFqR0V1r39W1KAI6hhsf5PVO3DG/ i/PHO+kNSTLDKplveOIr/kKmd9QyGMCFml8iY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=qQy7AVFfkbCRSsX49etjlHfxC49CU8vL33FvFW19nVQ=; b=DUFD8w6VWiX7Mcc2Fhc63vAeD3ZkfSX6KFJZELooRuvGnDY5ywTP+bDAg85aEaXUGG XjcfrjUELBxE9fKfNdmdWajwjKDggQRBz9mKXUXdDeEe8T/gc/lJdqp+GDNh0PhicvDB P7KPW3UalVYDgx/V9gxtrqlwmAlbBRmQ8pwZtShNWH/LuzgeHVxWKDz9wRCjcWMgDB1m Bh5GEQVZm/pTK0mhrTKsczCZG3zqGVp/V24dT0chCju1SCiY6gC14fecaQyOZXBm8kAo 1OWUVEdgYaUJN8ReyBP0DJMk9ACXLQnOhAAl7Ysjp9+CEyl6r5wVK8uXSzBySw3l2SQj /dLg== X-Gm-Message-State: AOAM530mrl2o9TtotbFPwX9njTLTj4oY7szAD6Lyz8GFN9EpIFMXft8U ss56sm//3K8eIonu60I13p8ngA== X-Google-Smtp-Source: ABdhPJxaQ/ho7jUYcCQxvL8m/NyC3MhWLmSyOq+EQ40aNNUGS7oo0hbfbozAOJWLt5UeYDP6T6fBrQ== X-Received: by 2002:a63:1619:: with SMTP id w25mr23810802pgl.34.1605141700803; Wed, 11 Nov 2020 16:41:40 -0800 (PST) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:42b0:34ff:fe3d:58e6]) by smtp.gmail.com with ESMTPSA id t26sm4265522pfl.72.2020.11.11.16.41.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Nov 2020 16:41:40 -0800 (PST) From: Douglas Anderson To: jkosina@suse.cz, benjamin.tissoires@redhat.com, gregkh@linuxfoundation.org, Dmitry Torokhov Cc: andrea@borgia.bo.it, robh+dt@kernel.org, kai.heng.feng@canonical.com, swboyd@chromium.org, linux-input@vger.kernel.org, hdegoede@redhat.com, Douglas Anderson , Aaron Ma , Jiri Kosina , Masahiro Yamada , Pavel Balan , Xiaofei Tan , You-Sheng Yang , linux-kernel@vger.kernel.org Subject: [PATCH v6 1/4] HID: i2c-hid: Reorganize so ACPI and OF are separate modules Date: Wed, 11 Nov 2020 16:41:27 -0800 Message-Id: <20201111164027.v6.1.Ied4ce10d229cd7c69abf13a0361ba0b8d82eb9c4@changeid> X-Mailer: git-send-email 2.29.2.222.g5d2a92d10f8-goog In-Reply-To: <20201112004130.17290-1-dianders@chromium.org> References: <20201112004130.17290-1-dianders@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org 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 Reviewed-by: Hans de Goede --- Changes in v6: - ACPI probe function should have been "static" - Don't export suspend/resume, just export dev_pm_ops from core. - Fixed crash in ACPI module (missing init of "client") - No need for regulator include in the core. - Removed i2c_device_id table from ACPI module. Changes in v5: - Add shutdown_tail op and use it in ACPI. - i2chid_subclass_data => i2chid_ops. - power_up_device => power_up (same with power_down). - subclass => ops. Changes in v4: - Fully rejigger so ACPI and OF are full subclasses. Changes in v3: - Rework to use subclassing. Changes in v2: - Get timings based on the compatible string. - Use a separate compatible string for this new touchscreen. drivers/hid/Makefile | 2 +- drivers/hid/i2c-hid/Kconfig | 32 +++- drivers/hid/i2c-hid/Makefile | 5 +- drivers/hid/i2c-hid/i2c-hid-acpi.c | 159 ++++++++++++++++ drivers/hid/i2c-hid/i2c-hid-core.c | 254 +++++--------------------- drivers/hid/i2c-hid/i2c-hid-of.c | 143 +++++++++++++++ drivers/hid/i2c-hid/i2c-hid.h | 22 +++ include/linux/platform_data/i2c-hid.h | 41 ----- 8 files changed, 397 insertions(+), 261 deletions(-) create mode 100644 drivers/hid/i2c-hid/i2c-hid-acpi.c create mode 100644 drivers/hid/i2c-hid/i2c-hid-of.c delete mode 100644 include/linux/platform_data/i2c-hid.h diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 4acb583c92a6..8d0c15a0d652 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -138,7 +138,7 @@ obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ obj-$(CONFIG_USB_KBD) += usbhid/ -obj-$(CONFIG_I2C_HID) += i2c-hid/ +obj-$(CONFIG_I2C_HID_CORE) += i2c-hid/ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig index c4e5dfeab2bd..819b7521c182 100644 --- a/drivers/hid/i2c-hid/Kconfig +++ b/drivers/hid/i2c-hid/Kconfig @@ -2,18 +2,40 @@ menu "I2C HID support" depends on I2C -config I2C_HID - tristate "HID over I2C transport layer" +config I2C_HID_ACPI + tristate "HID over I2C transport layer ACPI driver" default n - depends on I2C && INPUT - select HID + depends on I2C && INPUT && ACPI + help + Say Y here if you use a keyboard, a touchpad, a touchscreen, or any + other HID based devices which is connected to your computer via I2C. + This driver supports ACPI-based systems. + + If unsure, say N. + + This support is also available as a module. If so, the module + will be called i2c-hid-acpi. It will also build/depend on the + module i2c-hid. + +config I2C_HID_OF + tristate "HID over I2C transport layer Open Firmware driver" + default n + depends on I2C && INPUT && OF help Say Y here if you use a keyboard, a touchpad, a touchscreen, or any other HID based devices which is connected to your computer via I2C. + This driver supports Open Firmware (Device Tree)-based systems. If unsure, say N. This support is also available as a module. If so, the module - will be called i2c-hid. + will be called i2c-hid-of. It will also build/depend on the + module i2c-hid. endmenu + +config I2C_HID_CORE + tristate + default y if I2C_HID_ACPI=y || I2C_HID_OF=y + default m if I2C_HID_ACPI=m || I2C_HID_OF=m + select HID diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile index 681b3896898e..9b4a73446841 100644 --- a/drivers/hid/i2c-hid/Makefile +++ b/drivers/hid/i2c-hid/Makefile @@ -3,7 +3,10 @@ # Makefile for the I2C input drivers # -obj-$(CONFIG_I2C_HID) += i2c-hid.o +obj-$(CONFIG_I2C_HID_CORE) += i2c-hid.o i2c-hid-objs = i2c-hid-core.o i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o + +obj-$(CONFIG_I2C_HID_ACPI) += i2c-hid-acpi.o +obj-$(CONFIG_I2C_HID_OF) += i2c-hid-of.o diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.c b/drivers/hid/i2c-hid/i2c-hid-acpi.c new file mode 100644 index 000000000000..0f86060f01b4 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c @@ -0,0 +1,159 @@ +/* + * HID over I2C ACPI Subclass + * + * Copyright (c) 2012 Benjamin Tissoires + * 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 + * Copyright (c) 2005 Michael Haboustak 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 +#include +#include +#include +#include +#include + +#include "i2c-hid.h" + +struct i2c_hid_acpi { + struct i2chid_ops ops; + struct i2c_client *client; + bool power_fixed; +}; + +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 int i2c_hid_acpi_power_up(struct i2chid_ops *ops) +{ + struct i2c_hid_acpi *ihid_of = + container_of(ops, struct i2c_hid_acpi, ops); + struct device *dev = &ihid_of->client->dev; + struct acpi_device *adev; + + /* Only need to call acpi_device_fix_up_power() the first time */ + if (ihid_of->power_fixed) + return 0; + ihid_of->power_fixed = true; + + adev = ACPI_COMPANION(dev); + if (adev) + acpi_device_fix_up_power(adev); + + return 0; +} + +static void i2c_hid_acpi_shutdown_tail(struct i2chid_ops *ops) +{ + struct i2c_hid_acpi *ihid_of = + container_of(ops, struct i2c_hid_acpi, ops); + struct device *dev = &ihid_of->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; + 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.power_up = i2c_hid_acpi_power_up; + 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; + + 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 "); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index aeff1ffb0c8b..3962cb36e365 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -35,11 +35,6 @@ #include #include #include -#include -#include -#include - -#include #include "../hid-ids.h" #include "i2c-hid.h" @@ -156,10 +151,10 @@ struct i2c_hid { wait_queue_head_t wait; /* For waiting the interrupt */ - struct i2c_hid_platform_data pdata; - bool irq_wake_enabled; struct mutex reset_lock; + + struct i2chid_ops *ops; }; static const struct i2c_hid_quirks { @@ -884,144 +879,36 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) return 0; } -#ifdef CONFIG_ACPI -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_pdata(struct i2c_client *client, - struct i2c_hid_platform_data *pdata) -{ - 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; - - 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; - } - - pdata->hid_descriptor_address = obj->integer.value; - ACPI_FREE(obj); - - return 0; -} - -static void i2c_hid_acpi_fix_up_power(struct device *dev) -{ - struct acpi_device *adev; - - adev = ACPI_COMPANION(dev); - if (adev) - acpi_device_fix_up_power(adev); -} - -static void i2c_hid_acpi_enable_wakeup(struct device *dev) -{ - if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) { - device_set_wakeup_capable(dev, true); - device_set_wakeup_enable(dev, false); - } -} - -static void i2c_hid_acpi_shutdown(struct device *dev) +static int i2c_hid_core_power_up(struct i2c_hid *ihid) { - acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D3_COLD); -} + if (!ihid->ops->power_up) + return 0; -static const struct acpi_device_id i2c_hid_acpi_match[] = { - {"ACPI0C50", 0 }, - {"PNP0C50", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match); -#else -static inline int i2c_hid_acpi_pdata(struct i2c_client *client, - struct i2c_hid_platform_data *pdata) -{ - return -ENODEV; + return ihid->ops->power_up(ihid->ops); } -static inline void i2c_hid_acpi_fix_up_power(struct device *dev) {} - -static inline void i2c_hid_acpi_enable_wakeup(struct device *dev) {} - -static inline void i2c_hid_acpi_shutdown(struct device *dev) {} -#endif - -#ifdef CONFIG_OF -static int i2c_hid_of_probe(struct i2c_client *client, - struct i2c_hid_platform_data *pdata) +static void i2c_hid_core_power_down(struct i2c_hid *ihid) { - struct device *dev = &client->dev; - u32 val; - int ret; - - ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val); - if (ret) { - dev_err(&client->dev, "HID register address not provided\n"); - return -ENODEV; - } - if (val >> 16) { - dev_err(&client->dev, "Bad HID register address: 0x%08x\n", - val); - return -EINVAL; - } - pdata->hid_descriptor_address = val; - - return 0; -} + if (!ihid->ops->power_down) + return; -static const struct of_device_id i2c_hid_of_match[] = { - { .compatible = "hid-over-i2c" }, - {}, -}; -MODULE_DEVICE_TABLE(of, i2c_hid_of_match); -#else -static inline int i2c_hid_of_probe(struct i2c_client *client, - struct i2c_hid_platform_data *pdata) -{ - return -ENODEV; + ihid->ops->power_down(ihid->ops); } -#endif -static void i2c_hid_fwnode_probe(struct i2c_client *client, - struct i2c_hid_platform_data *pdata) +static void i2c_hid_core_shutdown_tail(struct i2c_hid *ihid) { - u32 val; + if (!ihid->ops->shutdown_tail) + return; - if (!device_property_read_u32(&client->dev, "post-power-on-delay-ms", - &val)) - pdata->post_power_delay_ms = val; + ihid->ops->shutdown_tail(ihid->ops); } -static int i2c_hid_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) +int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, + u16 hid_descriptor_address) { int ret; struct i2c_hid *ihid; struct hid_device *hid; - __u16 hidRegister; - struct i2c_hid_platform_data *platform_data = client->dev.platform_data; dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); @@ -1042,44 +929,17 @@ static int i2c_hid_probe(struct i2c_client *client, if (!ihid) return -ENOMEM; - if (client->dev.of_node) { - ret = i2c_hid_of_probe(client, &ihid->pdata); - if (ret) - return ret; - } else if (!platform_data) { - ret = i2c_hid_acpi_pdata(client, &ihid->pdata); - if (ret) - return ret; - } else { - ihid->pdata = *platform_data; - } - - /* Parse platform agnostic common properties from ACPI / device tree */ - i2c_hid_fwnode_probe(client, &ihid->pdata); - - ihid->pdata.supplies[0].supply = "vdd"; - ihid->pdata.supplies[1].supply = "vddl"; + ihid->ops = ops; - ret = devm_regulator_bulk_get(&client->dev, - ARRAY_SIZE(ihid->pdata.supplies), - ihid->pdata.supplies); + ret = i2c_hid_core_power_up(ihid); if (ret) return ret; - ret = regulator_bulk_enable(ARRAY_SIZE(ihid->pdata.supplies), - ihid->pdata.supplies); - if (ret < 0) - return ret; - - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); - i2c_set_clientdata(client, ihid); ihid->client = client; - hidRegister = ihid->pdata.hid_descriptor_address; - ihid->wHIDDescRegister = cpu_to_le16(hidRegister); + ihid->wHIDDescRegister = cpu_to_le16(hid_descriptor_address); init_waitqueue_head(&ihid->wait); mutex_init(&ihid->reset_lock); @@ -1089,11 +949,7 @@ static int i2c_hid_probe(struct i2c_client *client, * real computation later. */ ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE); if (ret < 0) - goto err_regulator; - - i2c_hid_acpi_fix_up_power(&client->dev); - - i2c_hid_acpi_enable_wakeup(&client->dev); + goto err_powered; device_enable_async_suspend(&client->dev); @@ -1102,16 +958,16 @@ static int i2c_hid_probe(struct i2c_client *client, if (ret < 0) { dev_dbg(&client->dev, "nothing at this address: %d\n", ret); ret = -ENXIO; - goto err_regulator; + goto err_powered; } ret = i2c_hid_fetch_hid_descriptor(ihid); if (ret < 0) - goto err_regulator; + goto err_powered; ret = i2c_hid_init_irq(client); if (ret < 0) - goto err_regulator; + goto err_powered; hid = hid_allocate_device(); if (IS_ERR(hid)) { @@ -1150,14 +1006,14 @@ static int i2c_hid_probe(struct i2c_client *client, err_irq: free_irq(client->irq, ihid); -err_regulator: - regulator_bulk_disable(ARRAY_SIZE(ihid->pdata.supplies), - ihid->pdata.supplies); +err_powered: + i2c_hid_core_power_down(ihid); i2c_hid_free_buffers(ihid); return ret; } +EXPORT_SYMBOL_GPL(i2c_hid_core_probe); -static int i2c_hid_remove(struct i2c_client *client) +int i2c_hid_core_remove(struct i2c_client *client) { struct i2c_hid *ihid = i2c_get_clientdata(client); struct hid_device *hid; @@ -1170,24 +1026,25 @@ static int i2c_hid_remove(struct i2c_client *client) if (ihid->bufsize) i2c_hid_free_buffers(ihid); - regulator_bulk_disable(ARRAY_SIZE(ihid->pdata.supplies), - ihid->pdata.supplies); + i2c_hid_core_power_down(ihid); return 0; } +EXPORT_SYMBOL_GPL(i2c_hid_core_remove); -static void i2c_hid_shutdown(struct i2c_client *client) +void i2c_hid_core_shutdown(struct i2c_client *client) { struct i2c_hid *ihid = i2c_get_clientdata(client); i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); free_irq(client->irq, ihid); - i2c_hid_acpi_shutdown(&client->dev); + i2c_hid_core_shutdown_tail(ihid); } +EXPORT_SYMBOL_GPL(i2c_hid_core_shutdown); #ifdef CONFIG_PM_SLEEP -static int i2c_hid_suspend(struct device *dev) +int i2c_hid_core_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct i2c_hid *ihid = i2c_get_clientdata(client); @@ -1214,14 +1071,14 @@ static int i2c_hid_suspend(struct device *dev) hid_warn(hid, "Failed to enable irq wake: %d\n", wake_status); } else { - regulator_bulk_disable(ARRAY_SIZE(ihid->pdata.supplies), - ihid->pdata.supplies); + i2c_hid_core_power_down(ihid); } return 0; } +EXPORT_SYMBOL_GPL(i2c_hid_core_suspend); -static int i2c_hid_resume(struct device *dev) +int i2c_hid_core_resume(struct device *dev) { int ret; struct i2c_client *client = to_i2c_client(dev); @@ -1230,13 +1087,7 @@ static int i2c_hid_resume(struct device *dev) int wake_status; if (!device_may_wakeup(&client->dev)) { - ret = regulator_bulk_enable(ARRAY_SIZE(ihid->pdata.supplies), - ihid->pdata.supplies); - if (ret) - hid_warn(hid, "Failed to enable supplies: %d\n", ret); - - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); + i2c_hid_core_power_up(ihid); } else if (ihid->irq_wake_enabled) { wake_status = disable_irq_wake(client->irq); if (!wake_status) @@ -1271,36 +1122,13 @@ static int i2c_hid_resume(struct device *dev) return 0; } +EXPORT_SYMBOL_GPL(i2c_hid_core_resume); #endif -static const struct dev_pm_ops i2c_hid_pm = { - SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_suspend, i2c_hid_resume) +const struct dev_pm_ops i2c_hid_core_pm = { + SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_core_suspend, i2c_hid_core_resume) }; - -static const struct i2c_device_id i2c_hid_id_table[] = { - { "hid", 0 }, - { "hid-over-i2c", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, i2c_hid_id_table); - - -static struct i2c_driver i2c_hid_driver = { - .driver = { - .name = "i2c_hid", - .pm = &i2c_hid_pm, - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match), - .of_match_table = of_match_ptr(i2c_hid_of_match), - }, - - .probe = i2c_hid_probe, - .remove = i2c_hid_remove, - .shutdown = i2c_hid_shutdown, - .id_table = i2c_hid_id_table, -}; - -module_i2c_driver(i2c_hid_driver); +EXPORT_SYMBOL_GPL(i2c_hid_core_pm); MODULE_DESCRIPTION("HID over I2C core driver"); MODULE_AUTHOR("Benjamin Tissoires "); diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c new file mode 100644 index 000000000000..4bf7cea92637 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-of.c @@ -0,0 +1,143 @@ +/* + * HID over I2C Open Firmware Subclass + * + * Copyright (c) 2012 Benjamin Tissoires + * 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 + * Copyright (c) 2005 Michael Haboustak 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 +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-hid.h" + +struct i2c_hid_of { + struct i2chid_ops ops; + + struct i2c_client *client; + struct regulator_bulk_data supplies[2]; + int post_power_delay_ms; +}; + +static int i2c_hid_of_power_up(struct i2chid_ops *ops) +{ + struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops); + struct device *dev = &ihid_of->client->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ihid_of->supplies), + ihid_of->supplies); + if (ret) { + dev_warn(dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + if (ihid_of->post_power_delay_ms) + msleep(ihid_of->post_power_delay_ms); + + return 0; +} + +static void i2c_hid_of_power_down(struct i2chid_ops *ops) +{ + struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops); + + regulator_bulk_disable(ARRAY_SIZE(ihid_of->supplies), + ihid_of->supplies); +} + +static int i2c_hid_of_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct device *dev = &client->dev; + struct i2c_hid_of *ihid_of; + u16 hid_descriptor_address; + int ret; + u32 val; + + ihid_of = devm_kzalloc(&client->dev, sizeof(*ihid_of), GFP_KERNEL); + if (!ihid_of) + return -ENOMEM; + + ihid_of->ops.power_up = i2c_hid_of_power_up; + ihid_of->ops.power_down = i2c_hid_of_power_down; + + ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val); + if (ret) { + dev_err(&client->dev, "HID register address not provided\n"); + return -ENODEV; + } + if (val >> 16) { + dev_err(&client->dev, "Bad HID register address: 0x%08x\n", + val); + return -EINVAL; + } + hid_descriptor_address = val; + + if (!device_property_read_u32(&client->dev, "post-power-on-delay-ms", + &val)) + ihid_of->post_power_delay_ms = val; + + ihid_of->supplies[0].supply = "vdd"; + ihid_of->supplies[1].supply = "vddl"; + ret = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(ihid_of->supplies), + ihid_of->supplies); + if (ret) + return ret; + + return i2c_hid_core_probe(client, &ihid_of->ops, + hid_descriptor_address); +} + +static const struct of_device_id i2c_hid_of_match[] = { + { .compatible = "hid-over-i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_hid_of_match); + +static const struct i2c_device_id i2c_hid_of_id_table[] = { + { "hid", 0 }, + { "hid-over-i2c", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, i2c_hid_of_id_table); + +static struct i2c_driver i2c_hid_of_driver = { + .driver = { + .name = "i2c_hid_of", + .pm = &i2c_hid_core_pm, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = of_match_ptr(i2c_hid_of_match), + }, + + .probe = i2c_hid_of_probe, + .remove = i2c_hid_core_remove, + .shutdown = i2c_hid_core_shutdown, + .id_table = i2c_hid_of_id_table, +}; + +module_i2c_driver(i2c_hid_of_driver); + +MODULE_DESCRIPTION("HID over I2C OF driver"); +MODULE_AUTHOR("Benjamin Tissoires "); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h index a8c19aef5824..05a7827d211a 100644 --- a/drivers/hid/i2c-hid/i2c-hid.h +++ b/drivers/hid/i2c-hid/i2c-hid.h @@ -3,6 +3,7 @@ #ifndef I2C_HID_H #define I2C_HID_H +#include #ifdef CONFIG_DMI struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name); @@ -17,4 +18,25 @@ static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, { return NULL; } #endif +/** + * struct i2chid_ops - Ops provided to the core. + * + * @power_up: do sequencing to power up the device. + * @power_down: do sequencing to power down the device. + * @shutdown_tail: called at the end of shutdown. + */ +struct i2chid_ops { + int (*power_up)(struct i2chid_ops *ops); + void (*power_down)(struct i2chid_ops *ops); + void (*shutdown_tail)(struct i2chid_ops *ops); +}; + +int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, + u16 hid_descriptor_address); +int i2c_hid_core_remove(struct i2c_client *client); + +void i2c_hid_core_shutdown(struct i2c_client *client); + +extern const struct dev_pm_ops i2c_hid_core_pm; + #endif diff --git a/include/linux/platform_data/i2c-hid.h b/include/linux/platform_data/i2c-hid.h deleted file mode 100644 index c628bb5e1061..000000000000 --- a/include/linux/platform_data/i2c-hid.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * HID over I2C protocol implementation - * - * Copyright (c) 2012 Benjamin Tissoires - * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France - * - * 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. - */ - -#ifndef __LINUX_I2C_HID_H -#define __LINUX_I2C_HID_H - -#include -#include - -/** - * struct i2chid_platform_data - used by hid over i2c implementation. - * @hid_descriptor_address: i2c register where the HID descriptor is stored. - * @supplies: regulators for powering on the device. - * @post_power_delay_ms: delay after powering on before device is usable. - * - * Note that it is the responsibility of the platform driver (or the acpi 5.0 - * driver, or the flattened device tree) to setup the irq related to the gpio in - * the struct i2c_board_info. - * The platform driver should also setup the gpio according to the device: - * - * A typical example is the following: - * irq = gpio_to_irq(intr_gpio); - * hkdk4412_i2c_devs5[0].irq = irq; // store the irq in i2c_board_info - * gpio_request(intr_gpio, "elan-irq"); - * s3c_gpio_setpull(intr_gpio, S3C_GPIO_PULL_UP); - */ -struct i2c_hid_platform_data { - u16 hid_descriptor_address; - struct regulator_bulk_data supplies[2]; - int post_power_delay_ms; -}; - -#endif /* __LINUX_I2C_HID_H */ From patchwork Thu Nov 12 00:41:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11898757 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 79B0A1668 for ; Thu, 12 Nov 2020 01:34:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 531E1208B3 for ; Thu, 12 Nov 2020 01:34:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="oYREcqIj" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728167AbgKLBeK (ORCPT ); Wed, 11 Nov 2020 20:34:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44468 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728129AbgKLAnQ (ORCPT ); Wed, 11 Nov 2020 19:43:16 -0500 Received: from mail-pf1-x441.google.com (mail-pf1-x441.google.com [IPv6:2607:f8b0:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 63375C061A4A for ; Wed, 11 Nov 2020 16:41:43 -0800 (PST) Received: by mail-pf1-x441.google.com with SMTP id z3so2868899pfb.10 for ; Wed, 11 Nov 2020 16:41:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=mjmuykYc+6IRfxhnFcBNshn4ZYHI8kwWAl9SmNJjnjo=; b=oYREcqIjRfeGgYSa+Ns0rz8Tfd1HDvVS0d5qrfnZXJnQVf5ySnqni8KSmbneWQMwWK TYgeRiLAAauZXt5IWSADfbMND/cBsxhNO1rcZPgNHImCUbOxmiPVJaapXKwXDh3VtaYl Hyh6GxKxYABOE9tfSgxuAEatQxAx1bcVBA1Gc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=mjmuykYc+6IRfxhnFcBNshn4ZYHI8kwWAl9SmNJjnjo=; b=IN6xG8ycjhULSaLDTmsAzwycfHoApdCQgnh86iJVOFTJN9QQ0qjQmYQB4fQFDANpxc 8XLW1aYkN5hmOiZ95yUiLMcRW4rGApPGS4BZCc2pSr6RkORsbDvQYknWNu02CQyI95Ra T+JGoUPUJuA9y5mb7iz3nPVNcvcU7T+e/xB3NM2YRRRxG4rmJk8aYQ2anRnWpkNNX17e E+o5JS3o4y080CTNVXlr+nOX0jHLA3GMHrErPiZt6EQj51mxbMPbx9mXC1ewXbg4wxo6 ynJKmw55LvLo2jRKNLCh9YR7QUm3qjsS+6Gn/B5PgHz7dAZhvgz0WBSM7MHAlt6hjPjS KYaQ== X-Gm-Message-State: AOAM532pZu/mzQyD/PO7a8v3dRV8Aqh7vIIvKi7wdgoNKk2oZezIUNda j5amr8pcN3iT67mm3gywFBUHOw== X-Google-Smtp-Source: ABdhPJxNiNr76eWFWPlZHLuQbAmuo6F5QkCNJ1QV8I9Pl2aPhpzBTSc7Kfd7HnXMo21gM8r5jGxEWg== X-Received: by 2002:a63:6a82:: with SMTP id f124mr270270pgc.236.1605141702977; Wed, 11 Nov 2020 16:41:42 -0800 (PST) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:42b0:34ff:fe3d:58e6]) by smtp.gmail.com with ESMTPSA id t26sm4265522pfl.72.2020.11.11.16.41.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Nov 2020 16:41:42 -0800 (PST) From: Douglas Anderson To: jkosina@suse.cz, benjamin.tissoires@redhat.com, gregkh@linuxfoundation.org, Dmitry Torokhov Cc: andrea@borgia.bo.it, robh+dt@kernel.org, kai.heng.feng@canonical.com, swboyd@chromium.org, linux-input@vger.kernel.org, hdegoede@redhat.com, Douglas Anderson , Anson Huang , Bjorn Andersson , Catalin Marinas , Geert Uytterhoeven , Krzysztof Kozlowski , Li Yang , Michael Walle , Olof Johansson , Shawn Guo , Vinod Koul , Will Deacon , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v6 2/4] arm64: defconfig: Update config names for i2c-hid rejigger Date: Wed, 11 Nov 2020 16:41:28 -0800 Message-Id: <20201111164027.v6.2.Ic9788bdfc4cce7569f8d25e7fb52a208fb643eac@changeid> X-Mailer: git-send-email 2.29.2.222.g5d2a92d10f8-goog In-Reply-To: <20201112004130.17290-1-dianders@chromium.org> References: <20201112004130.17290-1-dianders@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org The i2c-hid driver has been split in two. Let's enable both halves. Signed-off-by: Douglas Anderson --- (no changes since v4) Changes in v4: - ("arm64: defconfig: Update config names for i2c-hid rejigger") new for v4. arch/arm64/configs/defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 5cfe3cf6f2ac..9258d623331e 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -725,7 +725,8 @@ CONFIG_SND_SOC_WM8904=m CONFIG_SND_SOC_WSA881X=m CONFIG_SND_SIMPLE_CARD=m CONFIG_SND_AUDIO_GRAPH_CARD=m -CONFIG_I2C_HID=m +CONFIG_I2C_HID_ACPI=m +CONFIG_I2C_HID_OF=m CONFIG_USB_CONN_GPIO=m CONFIG_USB=y CONFIG_USB_OTG=y From patchwork Thu Nov 12 00:41:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11898759 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 84FD61391 for ; Thu, 12 Nov 2020 01:34:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5E6BD208B3 for ; Thu, 12 Nov 2020 01:34:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="CT6dNV+T" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728703AbgKLBeN (ORCPT ); Wed, 11 Nov 2020 20:34:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44534 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728131AbgKLAnl (ORCPT ); Wed, 11 Nov 2020 19:43:41 -0500 Received: from mail-pf1-x442.google.com (mail-pf1-x442.google.com [IPv6:2607:f8b0:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1B3FCC061A4C for ; Wed, 11 Nov 2020 16:41:45 -0800 (PST) Received: by mail-pf1-x442.google.com with SMTP id q5so2882774pfk.6 for ; Wed, 11 Nov 2020 16:41:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=DWB6g7SgUuqbksYreAE2hvC6FZMTkuUHQsnGWriw73M=; b=CT6dNV+TWZZNUscLwC6dmB5ywU+BaFJQKP7WJw3hJFcnFMEikPzugFMiwB/iH5Wlz+ 8bEJo8l+ztT0EllDbM8H+5EQNnyZS9Fbrjm38V/uMij8/MuNAWGwxlkOJfuFo6gypiHx zq9RMncewywXY+N1e8k66hCS3ihonZOc0wfOw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=DWB6g7SgUuqbksYreAE2hvC6FZMTkuUHQsnGWriw73M=; b=MD5392ZReUUF5ilFSX2ikXOwsOjTGjOSzmc5TObf6sYv1n/lvjt8GNu/YZGxllaGtX IF+UEb+y8P38rtbShawnhjhfA1wqthm/ak3iFTGaEkPfFkWkpuX5fUUS4o9EwXxVxMxN Oa6I4u1F2NpwSKlykF20785wpRuSKD2liRBiQQqC1YKcjWVKBtAh2Hn9++Sa1B3KEIGn kPWGvn7hdJ/UC1q06aZ5U4eWH5dSuEQLcCUJd53QH2BSA1ix2RLnnEObP89KEHF+KlUe FqRQtslnji/flNstRXI28idMguo5gtPN916u1JKhgWlenN2eGm2KZofFkskma4qJRila m69A== X-Gm-Message-State: AOAM532Uik6lyVGqqBfUUBJpoHCZXi+FBl2r4nlfDs3//AOjMelvQmhf cDICR9AyP2mXFr5qNul5Hao/XA== X-Google-Smtp-Source: ABdhPJwCNok+Lsh0ja3mTOu/Ky1lelVUsm/3MjwYBjN4SKOcugRW/jjW5QUZJgDXu5ShZPXd6OTJrg== X-Received: by 2002:a17:90b:33d1:: with SMTP id lk17mr6402941pjb.174.1605141704660; Wed, 11 Nov 2020 16:41:44 -0800 (PST) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:42b0:34ff:fe3d:58e6]) by smtp.gmail.com with ESMTPSA id t26sm4265522pfl.72.2020.11.11.16.41.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Nov 2020 16:41:44 -0800 (PST) From: Douglas Anderson To: jkosina@suse.cz, benjamin.tissoires@redhat.com, gregkh@linuxfoundation.org, Dmitry Torokhov Cc: andrea@borgia.bo.it, robh+dt@kernel.org, kai.heng.feng@canonical.com, swboyd@chromium.org, linux-input@vger.kernel.org, hdegoede@redhat.com, Douglas Anderson , Rob Herring , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v6 3/4] dt-bindings: input: HID: i2c-hid: Introduce bindings for the Goodix GT7375P Date: Wed, 11 Nov 2020 16:41:29 -0800 Message-Id: <20201111164027.v6.3.Ibb28033c81d87fcc13a6ba28c6ea7ac154d65f93@changeid> X-Mailer: git-send-email 2.29.2.222.g5d2a92d10f8-goog In-Reply-To: <20201112004130.17290-1-dianders@chromium.org> References: <20201112004130.17290-1-dianders@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org This adds new bindings for the Goodix GT7375P touchscreen. While this touchscreen's communications are based on the generic "i2c-over-hid" protocol, it needs special power sequencing and thus gets its own compatible and bindings. Signed-off-by: Douglas Anderson Reviewed-by: Rob Herring --- (no changes since v5) Changes in v5: - Added mention of i2c-hid in the yaml itself as per Rob. - Adjusted subject as per Rob. Changes in v3: - Fixed compatible in example. - Removed Benjamin as a maintainer. - Updated description. Changes in v2: - ("dt-bindings: HID: i2c-hid: Introduce bindings for the Goodix GT7375P") new in v2. .../bindings/input/goodix,gt7375p.yaml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/goodix,gt7375p.yaml diff --git a/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml b/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml new file mode 100644 index 000000000000..fe1c5016f7f3 --- /dev/null +++ b/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/goodix,gt7375p.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Goodix GT7375P touchscreen + +maintainers: + - Douglas Anderson + +description: + Supports the Goodix GT7375P touchscreen. + This touchscreen uses the i2c-hid protocol but has some non-standard + power sequencing required. + +properties: + compatible: + items: + - const: goodix,gt7375p + + reg: + enum: + - 0x5d + - 0x14 + + interrupts: + maxItems: 1 + + reset-gpios: + true + + vdd-supply: + description: The 3.3V supply to the touchscreen. + +required: + - compatible + - reg + - interrupts + - reset-gpios + - vdd-supply + +additionalProperties: false + +examples: + - | + #include + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ap_ts: touchscreen@5d { + compatible = "goodix,gt7375p"; + reg = <0x5d>; + + interrupt-parent = <&tlmm>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&tlmm 8 GPIO_ACTIVE_LOW>; + vdd-supply = <&pp3300_ts>; + }; + }; From patchwork Thu Nov 12 00:41:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11898761 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 338E016C0 for ; Thu, 12 Nov 2020 01:34:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0BF3220809 for ; Thu, 12 Nov 2020 01:34:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="Kd0H88a7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727535AbgKLBeO (ORCPT ); Wed, 11 Nov 2020 20:34:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44538 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728134AbgKLAnl (ORCPT ); Wed, 11 Nov 2020 19:43:41 -0500 Received: from mail-pf1-x444.google.com (mail-pf1-x444.google.com [IPv6:2607:f8b0:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0293C061A4E for ; Wed, 11 Nov 2020 16:41:46 -0800 (PST) Received: by mail-pf1-x444.google.com with SMTP id q10so2918922pfn.0 for ; Wed, 11 Nov 2020 16:41:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=bqfw24r492ZlSxiExdSPR4WpvJf90H3jjNhD9cbhKe0=; b=Kd0H88a7tX2w/XF97VJcyfSLioITcS6U4Zddl9PL7ktta7ezTd0xPlpztFCwTcbkA9 rJQMUhUMuSKgMFwobCIhMngzseuQaJ6jgeqPI8QUfBzda8fkd2LhBlYSQpDii5Qpkrlx p94rbWmQVWqn0yhPbUUnsULyNaHVl4lj8p0qE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bqfw24r492ZlSxiExdSPR4WpvJf90H3jjNhD9cbhKe0=; b=K9blTGIrgp8xaLt/SiGzjUUda/RkoSumECEN5tothRtf0Yjv6UCpAXj6HuKJOrq98C 54dNHTqMrMFjsstn0ZW18b9tcFndEnhN2L29xuoLV1DDl0TPql2KF40vcx5QQMPFj1WU ksyzVzxy7rAggGK9HIEBvj1HwcIhFN9HACZpuIWH5WXGzbldznDqyCJm6FiUzGGo4Lf2 8AE/T6glUOys1hgOjNg4iWYDjsawCJRirswLYGv+Zly1RymDQMuDZ5SS3CvcY02XCTzZ w6S+q7Xvcuyuu4pyGgw78dGzHDkBPv8mPlQnsIB7t0XV7n4Y7lDar6+VSVapKTQx1Caq Z0Pw== X-Gm-Message-State: AOAM531U9/HR+wmYFkdyj7llZ/JFWmJ5kpeA8CealTDoajdE5Yzd6CPJ k2/aeThXW4+TBkoqLx3R80TrRG7TFlERqw== X-Google-Smtp-Source: ABdhPJwwXgAkiVtxlKSqCTPPg/hu9iNiNZWvePJh4DhcPN2gseOgWuR4njAx+IRatgNPm805aFIijA== X-Received: by 2002:a62:6885:0:b029:164:51c0:b849 with SMTP id d127-20020a6268850000b029016451c0b849mr24990185pfc.58.1605141706374; Wed, 11 Nov 2020 16:41:46 -0800 (PST) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:42b0:34ff:fe3d:58e6]) by smtp.gmail.com with ESMTPSA id t26sm4265522pfl.72.2020.11.11.16.41.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Nov 2020 16:41:45 -0800 (PST) From: Douglas Anderson To: jkosina@suse.cz, benjamin.tissoires@redhat.com, gregkh@linuxfoundation.org, Dmitry Torokhov Cc: andrea@borgia.bo.it, robh+dt@kernel.org, kai.heng.feng@canonical.com, swboyd@chromium.org, linux-input@vger.kernel.org, hdegoede@redhat.com, Douglas Anderson , Jiri Kosina , Masahiro Yamada , linux-kernel@vger.kernel.org Subject: [PATCH v6 4/4] HID: i2c-hid: Introduce goodix-i2c-hid using i2c-hid core Date: Wed, 11 Nov 2020 16:41:30 -0800 Message-Id: <20201111164027.v6.4.If41b7d621633b94d56653c6d53f5f89c5274de7b@changeid> X-Mailer: git-send-email 2.29.2.222.g5d2a92d10f8-goog In-Reply-To: <20201112004130.17290-1-dianders@chromium.org> References: <20201112004130.17290-1-dianders@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Goodix i2c-hid touchscreens are mostly i2c-hid compliant but have some special power sequencing requirements, including the need to drive a reset line during the sequencing. Let's use the new rejiggering of i2c-hid to support this with a thin wrapper driver to support the first Goodix i2c-hid touchscreen: GT7375P Signed-off-by: Douglas Anderson --- Changes in v6: - Suspend/resume are no longer exported from the core. Changes in v5: - i2chid_subclass_data => i2chid_ops. - power_up_device => power_up (same with power_down). - subclass => ops. Changes in v4: - Totally redid based on the new subclass system. Changes in v3: - Rework to use subclassing. drivers/hid/i2c-hid/Kconfig | 19 +++- drivers/hid/i2c-hid/Makefile | 1 + drivers/hid/i2c-hid/i2c-hid-of-goodix.c | 116 ++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 drivers/hid/i2c-hid/i2c-hid-of-goodix.c diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig index 819b7521c182..a16c6a69680b 100644 --- a/drivers/hid/i2c-hid/Kconfig +++ b/drivers/hid/i2c-hid/Kconfig @@ -32,10 +32,25 @@ config I2C_HID_OF will be called i2c-hid-of. It will also build/depend on the module i2c-hid. +config I2C_HID_OF_GOODIX + tristate "Driver for Goodix hid-i2c based devices on OF systems" + default n + depends on I2C && INPUT && OF + help + Say Y here if you want support for Goodix i2c devices that use + the i2c-hid protocol on Open Firmware (Device Tree)-based + systems. + + If unsure, say N. + + This support is also available as a module. If so, the module + will be called i2c-hid-of-goodix. It will also build/depend on + the module i2c-hid. + endmenu config I2C_HID_CORE tristate - default y if I2C_HID_ACPI=y || I2C_HID_OF=y - default m if I2C_HID_ACPI=m || I2C_HID_OF=m + default y if I2C_HID_ACPI=y || I2C_HID_OF=y || I2C_HID_OF_GOODIX=y + default m if I2C_HID_ACPI=m || I2C_HID_OF=m || I2C_HID_OF_GOODIX=m select HID diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile index 9b4a73446841..302545a771f3 100644 --- a/drivers/hid/i2c-hid/Makefile +++ b/drivers/hid/i2c-hid/Makefile @@ -10,3 +10,4 @@ i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o obj-$(CONFIG_I2C_HID_ACPI) += i2c-hid-acpi.o obj-$(CONFIG_I2C_HID_OF) += i2c-hid-of.o +obj-$(CONFIG_I2C_HID_OF_GOODIX) += i2c-hid-of-goodix.o diff --git a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c new file mode 100644 index 000000000000..7cc51c25c609 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Goodix touchscreens that use the i2c-hid protocol. + * + * Copyright 2020 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-hid.h" + +struct goodix_i2c_hid_timing_data { + unsigned int post_gpio_reset_delay_ms; + unsigned int post_power_delay_ms; +}; + +struct i2c_hid_of_goodix { + struct i2chid_ops ops; + + struct regulator *vdd; + struct gpio_desc *reset_gpio; + const struct goodix_i2c_hid_timing_data *timings; +}; + +static int goodix_i2c_hid_power_up(struct i2chid_ops *ops) +{ + struct i2c_hid_of_goodix *ihid_goodix = + container_of(ops, struct i2c_hid_of_goodix, ops); + int ret; + + ret = regulator_enable(ihid_goodix->vdd); + if (ret) + return ret; + + if (ihid_goodix->timings->post_power_delay_ms) + msleep(ihid_goodix->timings->post_power_delay_ms); + + gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 0); + if (ihid_goodix->timings->post_gpio_reset_delay_ms) + msleep(ihid_goodix->timings->post_gpio_reset_delay_ms); + + return 0; +} + +static void goodix_i2c_hid_power_down(struct i2chid_ops *ops) +{ + struct i2c_hid_of_goodix *ihid_goodix = + container_of(ops, struct i2c_hid_of_goodix, ops); + + gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1); + regulator_disable(ihid_goodix->vdd); +} + +static int i2c_hid_of_goodix_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_hid_of_goodix *ihid_goodix; + + ihid_goodix = devm_kzalloc(&client->dev, sizeof(*ihid_goodix), + GFP_KERNEL); + if (!ihid_goodix) + return -ENOMEM; + + ihid_goodix->ops.power_up = goodix_i2c_hid_power_up; + ihid_goodix->ops.power_down = goodix_i2c_hid_power_down; + + /* Start out with reset asserted */ + ihid_goodix->reset_gpio = + devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ihid_goodix->reset_gpio)) + return PTR_ERR(ihid_goodix->reset_gpio); + + ihid_goodix->vdd = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(ihid_goodix->vdd)) + return PTR_ERR(ihid_goodix->vdd); + + ihid_goodix->timings = device_get_match_data(&client->dev); + + return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001); +} + +static const struct goodix_i2c_hid_timing_data goodix_gt7375p_timing_data = { + .post_power_delay_ms = 10, + .post_gpio_reset_delay_ms = 120, +}; + +static const struct of_device_id goodix_i2c_hid_of_match[] = { + { .compatible = "goodix,gt7375p", .data = &goodix_gt7375p_timing_data }, + { } +}; +MODULE_DEVICE_TABLE(of, goodix_i2c_hid_of_match); + +static struct i2c_driver goodix_i2c_hid_ts_driver = { + .driver = { + .name = "i2c_hid_of_goodix", + .pm = &i2c_hid_core_pm, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = of_match_ptr(goodix_i2c_hid_of_match), + }, + .probe = i2c_hid_of_goodix_probe, + .remove = i2c_hid_core_remove, + .shutdown = i2c_hid_core_shutdown, +}; +module_i2c_driver(goodix_i2c_hid_ts_driver); + +MODULE_AUTHOR("Douglas Anderson "); +MODULE_DESCRIPTION("Goodix i2c-hid touchscreen driver"); +MODULE_LICENSE("GPL v2");