From patchwork Mon Nov 9 21:36:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11892627 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 A1FFB1130 for ; Mon, 9 Nov 2020 21:37:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5BEFF206CB for ; Mon, 9 Nov 2020 21:37:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="WzXkQQFX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730482AbgKIVh2 (ORCPT ); Mon, 9 Nov 2020 16:37:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45004 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730331AbgKIVh1 (ORCPT ); Mon, 9 Nov 2020 16:37:27 -0500 Received: from mail-pf1-x42a.google.com (mail-pf1-x42a.google.com [IPv6:2607:f8b0:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 358C5C0613D3 for ; Mon, 9 Nov 2020 13:37:26 -0800 (PST) Received: by mail-pf1-x42a.google.com with SMTP id w14so6780549pfd.7 for ; Mon, 09 Nov 2020 13:37:26 -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=/h7p2KaVutiztzb9T8bbkTG62PDcDAR9yl+k61UDDsU=; b=WzXkQQFXR74rGMkWlzDxnbPBnNdjrg8+zSWA7nBi6RHr3vY+WILTjFxU6vhZd3yfe4 AML8+c6/UGaAIkpQlKSm8o8WzcEt0ONSyqCUmx6O2VNhXsQXl4LMCUkBOjOT6xkODqkA +MgKSMCKIZGltTcI9yKuXG06q8HQQ20HVE0ZQ= 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=/h7p2KaVutiztzb9T8bbkTG62PDcDAR9yl+k61UDDsU=; b=Ghalh2H5wA1gLBDKeAyE1FmmEiCkVia3jrxZFc8VNp6g1qhoFlkbf5mYx8xooMnzPB JvUiK8+FOfZ0dR/Qu5tpw0WKOHaIoAZgBUBGCL/lUdepL6Cdv47X4AU3AZC5ZoSt2cct K9T45QN19udPUbdVW6v8hMLIsR7sB2HVGYsh+OVd9WdfQKKyc7rrbh5HSGdSiABtX5Py NzeS+hJS0GqUKFkWnGO0W628J4nAPtNF+joHciJkjWWx5gCHlvaPgDmN17DFq7zrGqfo QnOExxo8PQcVLCJ0r7Ae4ooWlykpkjfVeQnn+enFXtxwbq6gXoVVzz72Fn+vnISnofxb XoHg== X-Gm-Message-State: AOAM533qxCHOfAzTLzpw7so7YfyLyBz+BtoVQ4CRbL5LW0NFDV13+OuP C0B1Ab0F//8+YOgLEnbfN2sElg== X-Google-Smtp-Source: ABdhPJxcCwVwbo0mJiTP5ncrjrLbVyhlF3qFVnhgG5/U9j94uHimNmAB4dOFgcjAFrv2opJb0lcR0A== X-Received: by 2002:a17:90b:30d2:: with SMTP id hi18mr1287580pjb.186.1604957845563; Mon, 09 Nov 2020 13:37:25 -0800 (PST) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:42b0:34ff:fe3d:58e6]) by smtp.gmail.com with ESMTPSA id i10sm11895444pfd.60.2020.11.09.13.37.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Nov 2020 13:37:24 -0800 (PST) From: Douglas Anderson To: jkosina@suse.cz, benjamin.tissoires@redhat.com, gregkh@linuxfoundation.org, Dmitry Torokhov Cc: kai.heng.feng@canonical.com, hdegoede@redhat.com, robh+dt@kernel.org, linux-input@vger.kernel.org, swboyd@chromium.org, andrea@borgia.bo.it, Douglas Anderson , Jiri Kosina , Masahiro Yamada , Pavel Balan , Xiaofei Tan , You-Sheng Yang , linux-kernel@vger.kernel.org Subject: [PATCH v5 1/4] HID: i2c-hid: Reorganize so ACPI and OF are separate modules Date: Mon, 9 Nov 2020 13:36:33 -0800 Message-Id: <20201109133526.v5.1.Ied4ce10d229cd7c69abf13a0361ba0b8d82eb9c4@changeid> X-Mailer: git-send-email 2.29.2.222.g5d2a92d10f8-goog In-Reply-To: <20201109213636.1267536-1-dianders@chromium.org> References: <20201109213636.1267536-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 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 | 170 +++++++++++++++++ drivers/hid/i2c-hid/i2c-hid-core.c | 252 ++++---------------------- drivers/hid/i2c-hid/i2c-hid-of.c | 147 +++++++++++++++ drivers/hid/i2c-hid/i2c-hid.h | 25 +++ include/linux/platform_data/i2c-hid.h | 41 ----- 8 files changed, 412 insertions(+), 262 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..5f09635d00ce --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c @@ -0,0 +1,170 @@ +/* + * 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); +} + +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->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 dev_pm_ops i2c_hid_acpi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_core_suspend, i2c_hid_core_resume) +}; + +static const struct acpi_device_id i2c_hid_acpi_match[] = { + {"ACPI0C50", 0 }, + {"PNP0C50", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match); + +static const struct i2c_device_id i2c_hid_acpi_id_table[] = { + { "hid", 0 }, + { "hid-over-i2c", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, i2c_hid_acpi_id_table); + +static struct i2c_driver i2c_hid_acpi_driver = { + .driver = { + .name = "i2c_hid_acpi", + .pm = &i2c_hid_acpi_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, + .id_table = i2c_hid_acpi_id_table, +}; + +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..9551ba96dc49 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -35,12 +35,8 @@ #include #include #include -#include -#include #include -#include - #include "../hid-ids.h" #include "i2c-hid.h" @@ -156,10 +152,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 +880,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 int i2c_hid_core_power_up(struct i2c_hid *ihid) { - 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) -{ - 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 +930,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->ops = ops; - ihid->pdata.supplies[0].supply = "vdd"; - ihid->pdata.supplies[1].supply = "vddl"; - - 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 +950,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 +959,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 +1007,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 +1027,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 +1072,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 +1088,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,37 +1123,9 @@ 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) -}; - -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); - MODULE_DESCRIPTION("HID over I2C core driver"); MODULE_AUTHOR("Benjamin Tissoires "); MODULE_LICENSE("GPL"); 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..15d533be2b24 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-of.c @@ -0,0 +1,147 @@ +/* + * 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 dev_pm_ops i2c_hid_of_pm = { + SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_core_suspend, i2c_hid_core_resume) +}; + +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_of_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..13e666ec366c 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,28 @@ 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); + +#ifdef CONFIG_PM_SLEEP +int i2c_hid_core_suspend(struct device *dev); +int i2c_hid_core_resume(struct device *dev); +#endif + #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 Mon Nov 9 21:36:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11892633 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 2F1021130 for ; Mon, 9 Nov 2020 21:37:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 02BDD2074F for ; Mon, 9 Nov 2020 21:37:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="O0sBObBD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730951AbgKIVhk (ORCPT ); Mon, 9 Nov 2020 16:37:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45010 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730470AbgKIVh2 (ORCPT ); Mon, 9 Nov 2020 16:37:28 -0500 Received: from mail-pf1-x443.google.com (mail-pf1-x443.google.com [IPv6:2607:f8b0:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2118BC0613CF for ; Mon, 9 Nov 2020 13:37:28 -0800 (PST) Received: by mail-pf1-x443.google.com with SMTP id a18so9219056pfl.3 for ; Mon, 09 Nov 2020 13:37:28 -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=O0sBObBD/WzQuzBqIR2UhdL8FFkQnNA9GsP3TcxSgLFceGhxzoW6rhgZtc9+Z0VqRl eI7YGS0ZYz3ZuMtT2HByZaf3O4z+HJH3a4ItXhNwm6xu3T87scQDCNTsM8EdpE4EBSWh 9F2wLWTJYvQ5Yhe5rnVMZpABhsQVxdh3oCLsU= 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=lM/udCIhAvd9+4Kxkr/1rMa1XOTeXr3mhSMmh3tU82pHRaP748dmHFvFYUKkHZIe26 IMyil4kSPn7SFdrnZphpBiEtlTBda2jnSljV9JCZvnYqCc6UYOuo5uzH8Xxjx9uzGDZ2 2hiv5EyeGTA/h5KGHuJMidX2n73Q0mpw+4Rr32UERxxh6U28S/HzULga7kdrhhijWwi5 /Nj6NvAdITg45ujfPfyOeSNhdIjNplGjfnFjn9fzcDS7hZobsLFvre+JYF8mHoi04T+b B2zy0bP3J8W6S0ZtVh7AcSI3VSyQeTQbwCuzDdXs2VN00oM4cj8eZf5fTIW50viQuKNE oIAA== X-Gm-Message-State: AOAM532Jy+eJOZDwP53TAIjiZbohPPRuLKKOY20VIlvoJazvqXU6+DLO cWrMdzC7XrsXL0ZSsCF+bPr+ag== X-Google-Smtp-Source: ABdhPJzZ1m/FD35icxSHf0g3HdP/6eAceyHUPH+V8QbGDISybPAEWMKP4NfP3Ty1AAlP25XTBbe5uw== X-Received: by 2002:a63:e40b:: with SMTP id a11mr14479882pgi.26.1604957847721; Mon, 09 Nov 2020 13:37:27 -0800 (PST) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:42b0:34ff:fe3d:58e6]) by smtp.gmail.com with ESMTPSA id i10sm11895444pfd.60.2020.11.09.13.37.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Nov 2020 13:37:27 -0800 (PST) From: Douglas Anderson To: jkosina@suse.cz, benjamin.tissoires@redhat.com, gregkh@linuxfoundation.org, Dmitry Torokhov Cc: kai.heng.feng@canonical.com, hdegoede@redhat.com, robh+dt@kernel.org, linux-input@vger.kernel.org, swboyd@chromium.org, andrea@borgia.bo.it, 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 v5 2/4] arm64: defconfig: Update config names for i2c-hid rejigger Date: Mon, 9 Nov 2020 13:36:34 -0800 Message-Id: <20201109133526.v5.2.Ic9788bdfc4cce7569f8d25e7fb52a208fb643eac@changeid> X-Mailer: git-send-email 2.29.2.222.g5d2a92d10f8-goog In-Reply-To: <20201109213636.1267536-1-dianders@chromium.org> References: <20201109213636.1267536-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 Mon Nov 9 21:36:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11892629 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 BF767139F for ; Mon, 9 Nov 2020 21:37:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 959D7206CB for ; Mon, 9 Nov 2020 21:37:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="KmSITxLJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730795AbgKIVhd (ORCPT ); Mon, 9 Nov 2020 16:37:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45020 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730664AbgKIVhb (ORCPT ); Mon, 9 Nov 2020 16:37:31 -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 32972C0613CF for ; Mon, 9 Nov 2020 13:37:30 -0800 (PST) Received: by mail-pf1-x442.google.com with SMTP id q5so6421388pfk.6 for ; Mon, 09 Nov 2020 13:37:30 -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=IVG/pnqU/rZNPf8FUWkusV/y8FFNBFgXush0QW0Xq5w=; b=KmSITxLJGqcCJ45deGdKGXIPpYDMb6vveRBn1HOVY6jEMgcT+ifQdB3G0Nal6I+V47 nSTUsnLUcQhMQAjWPDB5ap8OQYBYrtawZVjHw2D3ju1AoPvSRxJdOZ9mARnXlcbQxadC JD2D6wyu2ywUArSYM5EzsEt9IEcySkh9UqOds= 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=IVG/pnqU/rZNPf8FUWkusV/y8FFNBFgXush0QW0Xq5w=; b=Pi7oxyXGnbYxPan8v2bCC80EcTUXIBikwNobDuTPwlhzLIJVY3bTAfN9PmoifvLu5d We+Ii48QtXfRMitR745xOYESKS3Pli1P/Ggn1CV/cRp6+U+gr7gn40O6QMgD6MQuHbNG YXox2BXU9KRr30OEjioWbK/rhYXTaw8jHB+8iy+tEBHJx18sljjFO27uoq5npZzZVfWe 5CCocy/jMgxpbsgfw5WVxeIvtkxPemh+RMN4sGiwwUPkwW7NmwyzJEU9dByKto5J5vpF TLaV6VV6imdoQ6DyMK1LsX67W8wNGXi0dihrHk3sajZzgbLK9x2C9w1arGfeQwb7iPh0 crcQ== X-Gm-Message-State: AOAM532xbEXro0bxBIihsWRfDwGg9qgDS6YeReJo1xZ08JNGtUlP3Nmw k+cFgMP1l748Wb6ghKbKORA/Gg== X-Google-Smtp-Source: ABdhPJzzp3X12Puhdm2/cXoL8BUDk0MNJMipPzxDxixAaij3gk3beeDcDcKSGToa7LMwwY12Zd1gUw== X-Received: by 2002:a63:134d:: with SMTP id 13mr14444377pgt.370.1604957849726; Mon, 09 Nov 2020 13:37:29 -0800 (PST) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:42b0:34ff:fe3d:58e6]) by smtp.gmail.com with ESMTPSA id i10sm11895444pfd.60.2020.11.09.13.37.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Nov 2020 13:37:29 -0800 (PST) From: Douglas Anderson To: jkosina@suse.cz, benjamin.tissoires@redhat.com, gregkh@linuxfoundation.org, Dmitry Torokhov Cc: kai.heng.feng@canonical.com, hdegoede@redhat.com, robh+dt@kernel.org, linux-input@vger.kernel.org, swboyd@chromium.org, andrea@borgia.bo.it, Douglas Anderson , Rob Herring , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 3/4] dt-bindings: input: HID: i2c-hid: Introduce bindings for the Goodix GT7375P Date: Mon, 9 Nov 2020 13:36:35 -0800 Message-Id: <20201109133526.v5.3.Ibb28033c81d87fcc13a6ba28c6ea7ac154d65f93@changeid> X-Mailer: git-send-email 2.29.2.222.g5d2a92d10f8-goog In-Reply-To: <20201109213636.1267536-1-dianders@chromium.org> References: <20201109213636.1267536-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 --- 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 Mon Nov 9 21:36:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11892631 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 0523F14C0 for ; Mon, 9 Nov 2020 21:37:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D2DCF206CB for ; Mon, 9 Nov 2020 21:37:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="bfjg3Fat" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730738AbgKIVhi (ORCPT ); Mon, 9 Nov 2020 16:37:38 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45026 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730664AbgKIVhd (ORCPT ); Mon, 9 Nov 2020 16:37:33 -0500 Received: from mail-pg1-x544.google.com (mail-pg1-x544.google.com [IPv6:2607:f8b0:4864:20::544]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CCCE6C0613D3 for ; Mon, 9 Nov 2020 13:37:31 -0800 (PST) Received: by mail-pg1-x544.google.com with SMTP id h6so8276630pgk.4 for ; Mon, 09 Nov 2020 13:37:31 -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=NNRoLoYxkiRimKsamtR/wU4I4Dy9u1TxkiK2Eke0Tfw=; b=bfjg3FatzGJrrZHH0ICfFXfngMqbBU+llsM81m0qIG53sJeyiUX9l4y2R/GVVJrEpt eFItP2te8xKVVrHYwQg64jVPa2Zzcixv5iYDgg3Md8EKh8H89IxWPUC9OOFkhv9hnoLB dsP8N+PN3s+N9Wsw5sPm41hAfj8STukToim6k= 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=NNRoLoYxkiRimKsamtR/wU4I4Dy9u1TxkiK2Eke0Tfw=; b=sIbhLiQF8jxP8J2zghrtxW8bF9yjGlMCKGJEsVhg+1GyLk/vuEc7EPSBDFaxd3AE19 pHJ4p60J4wwkKz+zCWtXUn4u6J1xtp5eougfXaJhLnqgn+tokwJMRwrKQsav+OchY3BZ ZXmsmvjVegZHRnIDpHmRtzsGEAoMBvw+V1uN3moG34B1f/rkKGAIgg7ZBIVvEli9p1JO qNeA1P5ly8AdfoyEmzG3n6DELaXcWC0OlBqR+0TeBXgqLNzcyO4Xk1nHQYGLwy6YYRlF +pZEEXM1LKbgOZkRWgcWhbk/KANHZVdp1pl1oRCPZDMGlN6ccr6crHeMmZesxbp/cxjF CXHA== X-Gm-Message-State: AOAM530IZ6wjv0QYEY5m5OooaDjhNk/6a/1RRVWzJHNfP7kBTXuz/wRf mx0d7vJlpjs2+HMuHXrHcocoeg== X-Google-Smtp-Source: ABdhPJznpCe2sDSveeqw0m0xkUaskz2FwjzpSPbc2o5kC/jt6E+Lz+HSJmKAcqy7lblc6/wlJYW6QQ== X-Received: by 2002:a63:ef4f:: with SMTP id c15mr14441624pgk.345.1604957851388; Mon, 09 Nov 2020 13:37:31 -0800 (PST) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:42b0:34ff:fe3d:58e6]) by smtp.gmail.com with ESMTPSA id i10sm11895444pfd.60.2020.11.09.13.37.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Nov 2020 13:37:30 -0800 (PST) From: Douglas Anderson To: jkosina@suse.cz, benjamin.tissoires@redhat.com, gregkh@linuxfoundation.org, Dmitry Torokhov Cc: kai.heng.feng@canonical.com, hdegoede@redhat.com, robh+dt@kernel.org, linux-input@vger.kernel.org, swboyd@chromium.org, andrea@borgia.bo.it, Douglas Anderson , Jiri Kosina , Masahiro Yamada , linux-kernel@vger.kernel.org Subject: [PATCH v5 4/4] HID: i2c-hid: Introduce goodix-i2c-hid using i2c-hid core Date: Mon, 9 Nov 2020 13:36:36 -0800 Message-Id: <20201109133526.v5.4.If41b7d621633b94d56653c6d53f5f89c5274de7b@changeid> X-Mailer: git-send-email 2.29.2.222.g5d2a92d10f8-goog In-Reply-To: <20201109213636.1267536-1-dianders@chromium.org> References: <20201109213636.1267536-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 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 | 120 ++++++++++++++++++++++++ 3 files changed, 138 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..eada0363ef62 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c @@ -0,0 +1,120 @@ +// 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 const struct dev_pm_ops goodix_i2c_hid_pm = { + SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_core_suspend, i2c_hid_core_resume) +}; + +static struct i2c_driver goodix_i2c_hid_ts_driver = { + .driver = { + .name = "i2c_hid_of_goodix", + .pm = &goodix_i2c_hid_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");