From patchwork Wed Apr 3 16:45:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884223 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C145A1390 for ; Wed, 3 Apr 2019 16:46:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AAF17202A5 for ; Wed, 3 Apr 2019 16:46:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9F66427FA8; Wed, 3 Apr 2019 16:46:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 596B7202A5 for ; Wed, 3 Apr 2019 16:46:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728771AbfDCQpn (ORCPT ); Wed, 3 Apr 2019 12:45:43 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726920AbfDCQpn (ORCPT ); Wed, 3 Apr 2019 12:45:43 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:45:42 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077282" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:45:40 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 01/11] software node: Allow node creation without properties Date: Wed, 3 Apr 2019 19:45:27 +0300 Message-Id: <20190403164537.24643-2-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Software nodes are not forced to have device properties. Adding check to property_entries_dup() to make it possible to create software nodes that don't have any properties. Signed-off-by: Heikki Krogerus --- drivers/base/swnode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 7fc5a18e02ad..30077454eb68 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -383,6 +383,9 @@ property_entries_dup(const struct property_entry *properties) int i, n = 0; int ret; + if (!properties) + return NULL; + while (properties[n].name) n++; From patchwork Wed Apr 3 16:45:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884219 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 47DDA17E0 for ; Wed, 3 Apr 2019 16:46:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 314E627FA8 for ; Wed, 3 Apr 2019 16:46:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2593027FB1; Wed, 3 Apr 2019 16:46:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B8F4D2522B for ; Wed, 3 Apr 2019 16:46:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727027AbfDCQpq (ORCPT ); Wed, 3 Apr 2019 12:45:46 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728863AbfDCQpp (ORCPT ); Wed, 3 Apr 2019 12:45:45 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:45:45 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077310" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:45:43 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 02/11] software node: Simplify software_node_release() function Date: Wed, 3 Apr 2019 19:45:28 +0300 Message-Id: <20190403164537.24643-3-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP It's possible to release the node ID immediately when fwnode_remove_software_node() is called, no need to wait for software_node_release() with that. This change has no functional effect. Signed-off-by: Heikki Krogerus --- drivers/base/swnode.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 30077454eb68..7b321bf8424c 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -557,13 +557,6 @@ static void software_node_release(struct kobject *kobj) { struct software_node *swnode = kobj_to_swnode(kobj); - if (swnode->parent) { - ida_simple_remove(&swnode->parent->child_ids, swnode->id); - list_del(&swnode->entry); - } else { - ida_simple_remove(&swnode_root_ids, swnode->id); - } - ida_destroy(&swnode->child_ids); property_entries_free(swnode->properties); kfree(swnode); @@ -610,9 +603,6 @@ fwnode_create_software_node(const struct property_entry *properties, INIT_LIST_HEAD(&swnode->children); swnode->parent = p; - if (p) - list_add_tail(&swnode->entry, &p->children); - ret = kobject_init_and_add(&swnode->kobj, &software_node_type, p ? &p->kobj : NULL, "node%d", swnode->id); if (ret) { @@ -626,6 +616,9 @@ fwnode_create_software_node(const struct property_entry *properties, return ERR_PTR(ret); } + if (p) + list_add_tail(&swnode->entry, &p->children); + kobject_uevent(&swnode->kobj, KOBJ_ADD); return &swnode->fwnode; } @@ -638,6 +631,13 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode) if (!swnode) return; + if (swnode->parent) { + ida_simple_remove(&swnode->parent->child_ids, swnode->id); + list_del(&swnode->entry); + } else { + ida_simple_remove(&swnode_root_ids, swnode->id); + } + kobject_put(&swnode->kobj); } EXPORT_SYMBOL_GPL(fwnode_remove_software_node); From patchwork Wed Apr 3 16:45:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884179 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E946217E0 for ; Wed, 3 Apr 2019 16:45:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CE625289AA for ; Wed, 3 Apr 2019 16:45:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C261F28A0A; Wed, 3 Apr 2019 16:45:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1A78F289AA for ; Wed, 3 Apr 2019 16:45:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728553AbfDCQpt (ORCPT ); Wed, 3 Apr 2019 12:45:49 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728766AbfDCQps (ORCPT ); Wed, 3 Apr 2019 12:45:48 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:45:48 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077333" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:45:45 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 03/11] software node: Add support for references Date: Wed, 3 Apr 2019 19:45:29 +0300 Message-Id: <20190403164537.24643-4-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Introducing functions that can be used for adding and removing references to other software nodes. The goal is to support fwnode_property_get_reference_args() also with software nodes, however, get_reference_args fwnode operation callback is not yet implemented in this commit for the software nodes. This commit will only add support for reference addition/removal. The next example shows how to add references to GPIOs using the format described in Documentation/acpi/gpio-properties.txt: /* Array with two GPIOs */ static struct fwnode_reference_args gpioargs[] __initdata = { { .nargs = 3, .args[0]= 19, /* index */ .args[1]= 0, /* pin */ .args[2]= 0, /* active_low */ }, { .nargs = 3, .args[0]= 20, /* index */ .args[1]= 0, /* pin */ .args[2]= 0, /* active_low */ }, { } }; static int myinit(void) { struct software_node_reference *ref; struct fwnode_handle *gpio_node; struct fwnode_handle *my_node; /* Creating the nodes */ gpio_node = fwnode_create_software_node(gpio_props, NULL); ... my_node = fwnode_create_software_node(my_props, NULL); ... /* gpio_node is associated with a GPIO/Pin controller in this example */ ... /* Assigning the actual node references */ gpioargs[0].fwnode = gpio_node; gpioargs[1].fwnode = gpio_node; /* my_node will now have a named ("gpios") reference to the two GPIOs */ ref = fwnode_create_software_node_reference(my_node, "gpios", gpioargs); ... return 0; } Signed-off-by: Heikki Krogerus --- drivers/base/swnode.c | 101 +++++++++++++++++++++++++++++++++++++++ include/linux/property.h | 8 ++++ 2 files changed, 109 insertions(+) diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 7b321bf8424c..39b8f8f35cfe 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -11,10 +11,19 @@ #include #include +struct software_node_reference { + struct list_head list; + const char *name; + int nrefs; + struct fwnode_reference_args *args; +}; + struct software_node { int id; struct kobject kobj; struct fwnode_handle fwnode; + struct list_head references; + struct mutex lock; /* node lock */ /* hierarchy */ struct ida child_ids; @@ -598,9 +607,11 @@ fwnode_create_software_node(const struct property_entry *properties, swnode->kobj.kset = swnode_kset; swnode->fwnode.ops = &software_node_ops; + mutex_init(&swnode->lock); ida_init(&swnode->child_ids); INIT_LIST_HEAD(&swnode->entry); INIT_LIST_HEAD(&swnode->children); + INIT_LIST_HEAD(&swnode->references); swnode->parent = p; ret = kobject_init_and_add(&swnode->kobj, &software_node_type, @@ -631,6 +642,11 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode) if (!swnode) return; + mutex_lock(&swnode->lock); + WARN(!list_empty(&swnode->references), + "\"%s\" has still references", kobject_name(&swnode->kobj)); + mutex_unlock(&swnode->lock); + if (swnode->parent) { ida_simple_remove(&swnode->parent->child_ids, swnode->id); list_del(&swnode->entry); @@ -642,6 +658,91 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fwnode_remove_software_node); +/** + * fwnode_create_software_node_reference - Create named reference description + * @fwnode: The software node to have the references + * @name: Name given to reference description + * @args: Zero terminated array of software node references with arguments + * + * Associates software nodes listed in @args with @fwnode. The association is + * named @name. The reference count is incremented for the nodes in @args. + * + * Returns pointer to software node reference description on success, or ERR_PTR + * on failure. + */ +struct software_node_reference * +fwnode_create_software_node_reference(const struct fwnode_handle *fwnode, + const char *name, + const struct fwnode_reference_args *args) +{ + struct software_node *swnode = to_software_node(fwnode); + struct software_node_reference *ref; + int n; + + if (!swnode) + return ERR_PTR(-EINVAL); + + for (n = 0; args[n].fwnode; n++) + if (!is_software_node(args[n].fwnode)) + return ERR_PTR(-EINVAL); + + ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!ref) + return ERR_PTR(-ENOMEM); + + ref->nrefs = n; + + ref->name = kstrdup(name, GFP_KERNEL); + if (!ref->name) { + kfree(ref); + return ERR_PTR(-ENOMEM); + } + + ref->args = kcalloc(ref->nrefs, sizeof(*ref->args), GFP_KERNEL); + if (!ref->args) { + kfree(ref->name); + kfree(ref); + return ERR_PTR(-ENOMEM); + } + + for (n = 0; n < ref->nrefs; n++) { + ref->args[n] = args[n]; + software_node_get(ref->args[n].fwnode); + } + + mutex_lock(&swnode->lock); + list_add_tail(&ref->list, &swnode->references); + mutex_unlock(&swnode->lock); + + return ref; +} +EXPORT_SYMBOL_GPL(fwnode_create_software_node_reference); + +/** + * fwnode_remove_software_node_reference - Remove named reference description + * @ref: Software node reference description + * + * Remove named reference @ref. Decrements the software node reference count of + * each node in @ref, and removes the association that was created in + * fwnode_create_software_node_reference(). + */ +void fwnode_remove_software_node_reference(struct software_node_reference *ref) +{ + int n; + + if (IS_ERR_OR_NULL(ref)) + return; + + for (n = 0; n < ref->nrefs; n++) + kobject_put(&to_software_node(ref->args[n].fwnode)->kobj); + + list_del(&ref->list); + kfree(ref->args); + kfree(ref->name); + kfree(ref); +} +EXPORT_SYMBOL_GPL(fwnode_remove_software_node_reference); + int software_node_notify(struct device *dev, unsigned long action) { struct fwnode_handle *fwnode = dev_fwnode(dev); diff --git a/include/linux/property.h b/include/linux/property.h index 65d3420dd5d1..40e12ca43556 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -314,6 +314,8 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, /* -------------------------------------------------------------------------- */ /* Software fwnode support - when HW description is incomplete or missing */ +struct sofware_node_reference; + bool is_software_node(const struct fwnode_handle *fwnode); int software_node_notify(struct device *dev, unsigned long action); @@ -323,4 +325,10 @@ fwnode_create_software_node(const struct property_entry *properties, const struct fwnode_handle *parent); void fwnode_remove_software_node(struct fwnode_handle *fwnode); +struct software_node_reference * +fwnode_create_software_node_reference(const struct fwnode_handle *fwnode, + const char *name, + const struct fwnode_reference_args *args); +void fwnode_remove_software_node_reference(struct software_node_reference *ref); + #endif /* _LINUX_PROPERTY_H_ */ From patchwork Wed Apr 3 16:45:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884183 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 47B251390 for ; Wed, 3 Apr 2019 16:45:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 323E828990 for ; Wed, 3 Apr 2019 16:45:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 26E78289FC; Wed, 3 Apr 2019 16:45:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C60C728990 for ; Wed, 3 Apr 2019 16:45:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728760AbfDCQpw (ORCPT ); Wed, 3 Apr 2019 12:45:52 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728886AbfDCQpu (ORCPT ); Wed, 3 Apr 2019 12:45:50 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:45:50 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077358" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:45:48 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 04/11] software node: Implement .get_reference_args fwnode operation Date: Wed, 3 Apr 2019 19:45:30 +0300 Message-Id: <20190403164537.24643-5-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This makes it possible to support drivers that use fwnode_property_get_reference_args() function. Signed-off-by: Heikki Krogerus --- drivers/base/swnode.c | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 39b8f8f35cfe..d6a9b56cb073 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -534,6 +534,61 @@ software_node_get_named_child_node(const struct fwnode_handle *fwnode, return NULL; } +static int +software_node_get_reference_args(const struct fwnode_handle *fwnode, + const char *propname, const char *nargs_prop, + unsigned int nargs, unsigned int index, + struct fwnode_reference_args *args) +{ + struct software_node *swnode = to_software_node(fwnode); + struct software_node_reference *ref; + const struct property_entry *prop; + int ret = -ENOENT; + int i; + + mutex_lock(&swnode->lock); + + if (!swnode || list_empty(&swnode->references)) + goto err_unlock; + + if (nargs_prop) { + prop = property_entry_get(swnode->properties, nargs_prop); + if (!prop) { + ret = -EINVAL; + goto err_unlock; + } + + nargs = prop->value.u32_data; + } + + if (nargs > NR_FWNODE_REFERENCE_ARGS) { + ret = -EINVAL; + goto err_unlock; + } + + list_for_each_entry(ref, &swnode->references, list) { + if (strcmp(ref->name, propname)) + continue; + + if (index > (ref->nrefs - 1)) + break; + + args->nargs = nargs; + args->fwnode = software_node_get(ref->args[index].fwnode); + + for (i = 0; i < nargs; i++) + args->args[i] = ref->args[index].args[i]; + + ret = 0; + break; + } + +err_unlock: + mutex_unlock(&swnode->lock); + + return ret; +} + static const struct fwnode_operations software_node_ops = { .get = software_node_get, .put = software_node_put, @@ -543,6 +598,7 @@ static const struct fwnode_operations software_node_ops = { .get_parent = software_node_get_parent, .get_next_child_node = software_node_get_next_child, .get_named_child_node = software_node_get_named_child_node, + .get_reference_args = software_node_get_reference_args, }; /* -------------------------------------------------------------------------- */ From patchwork Wed Apr 3 16:45:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884213 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 521C117EE for ; Wed, 3 Apr 2019 16:46:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3BD212522B for ; Wed, 3 Apr 2019 16:46:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2FD7B2821F; Wed, 3 Apr 2019 16:46:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D49172522B for ; Wed, 3 Apr 2019 16:46:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728901AbfDCQpy (ORCPT ); Wed, 3 Apr 2019 12:45:54 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728658AbfDCQpy (ORCPT ); Wed, 3 Apr 2019 12:45:54 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:45:53 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077385" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:45:50 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 05/11] ACPI / property: Don't limit named child node matching to data nodes Date: Wed, 3 Apr 2019 19:45:31 +0300 Message-Id: <20190403164537.24643-6-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP There is no reason why we should limit the use of fwnode_get_named_child_node() to data nodes only. Signed-off-by: Heikki Krogerus --- drivers/acpi/property.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 77abe0ec4043..c3fb52c387a6 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -602,15 +602,29 @@ static struct fwnode_handle * acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, const char *childname) { + char name[ACPI_PATH_SEGMENT_LENGTH]; struct fwnode_handle *child; + struct acpi_buffer path; + acpi_status status; - /* - * Find first matching named child node of this fwnode. - * For ACPI this will be a data only sub-node. - */ - fwnode_for_each_child_node(fwnode, child) - if (acpi_data_node_match(child, childname)) + path.length = sizeof(name); + path.pointer = name; + + fwnode_for_each_child_node(fwnode, child) { + if (is_acpi_data_node(child)) { + if (acpi_data_node_match(child, childname)) + return child; + continue; + } + + status = acpi_get_name(ACPI_HANDLE_FWNODE(child), + ACPI_SINGLE_NAME, &path); + if (ACPI_FAILURE(status)) + break; + + if (!strncmp(name, childname, ACPI_NAME_SIZE)) return child; + } return NULL; } From patchwork Wed Apr 3 16:45:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884185 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C1F6F1390 for ; Wed, 3 Apr 2019 16:46:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AD39F28990 for ; Wed, 3 Apr 2019 16:46:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A1B9D289F3; Wed, 3 Apr 2019 16:46:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E8FBD28A08 for ; Wed, 3 Apr 2019 16:46:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728744AbfDCQqB (ORCPT ); Wed, 3 Apr 2019 12:46:01 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728758AbfDCQp4 (ORCPT ); Wed, 3 Apr 2019 12:45:56 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:45:55 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077405" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:45:53 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 06/11] device connection: Find connections also by checking the references Date: Wed, 3 Apr 2019 19:45:32 +0300 Message-Id: <20190403164537.24643-7-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP We can also use this API to find named references that the device nodes have by using fwnode_property_get_reference_args() function. Signed-off-by: Heikki Krogerus --- drivers/base/devcon.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c index 04db9ae235e4..4cdf95532b63 100644 --- a/drivers/base/devcon.c +++ b/drivers/base/devcon.c @@ -38,6 +38,30 @@ fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id, return NULL; } +static void * +fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id, + void *data, devcon_match_fn_t match) +{ + struct device_connection con = { }; + struct fwnode_reference_args args; + void *ret; + int i; + + for (i = 0; ; i++) { + if (fwnode_property_get_reference_args(fwnode, con_id, NULL, 0, + i, &args)) + break; + + con.fwnode = args.fwnode; + ret = match(&con, -1, data); + fwnode_handle_put(args.fwnode); + if (ret) + return ret; + } + + return NULL; +} + /** * device_connection_find_match - Find physical connection to a device * @dev: Device with the connection @@ -65,6 +89,10 @@ void *device_connection_find_match(struct device *dev, const char *con_id, ret = fwnode_graph_devcon_match(fwnode, con_id, data, match); if (ret) return ret; + + ret = fwnode_devcon_match(fwnode, con_id, data, match); + if (ret) + return ret; } mutex_lock(&devcon_lock); From patchwork Wed Apr 3 16:45:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884209 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 061561390 for ; Wed, 3 Apr 2019 16:46:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E161427FA8 for ; Wed, 3 Apr 2019 16:46:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D4CC92897F; Wed, 3 Apr 2019 16:46:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A32D827FA8 for ; Wed, 3 Apr 2019 16:46:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726099AbfDCQqj (ORCPT ); Wed, 3 Apr 2019 12:46:39 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726988AbfDCQqB (ORCPT ); Wed, 3 Apr 2019 12:46:01 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:45:59 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077434" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:45:55 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 07/11] usb: typec: Registering real device entries for the muxes Date: Wed, 3 Apr 2019 19:45:33 +0300 Message-Id: <20190403164537.24643-8-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Registering real device entries (struct device) for the mode muxes as well as for the orientation switches. The Type-C mux code was deliberately attempting to avoid creation of separate device entries for the orientation switch and the mode switch (alternate modes) because they are not physical devices. They are functions of a single physical multiplexer/demultiplexer switch device. Unfortunately because of the dependency we still have on the underlying mux device driver, we had to put in hacks like the one in the commit 3e3b81965cbf ("usb: typec: mux: Take care of driver module reference counting") to make sure the driver does not disappear from underneath us. Even with those hacks we were still left with a potential NUll pointer dereference scenario, so just creating the device entries, and letting the core take care of the dependencies. No more hacks needed. Signed-off-by: Heikki Krogerus --- drivers/platform/x86/intel_cht_int33fe.c | 4 +- drivers/usb/typec/bus.h | 15 ++ drivers/usb/typec/class.c | 17 +- drivers/usb/typec/mux.c | 221 ++++++++++++++++------- drivers/usb/typec/mux/pi3usb30532.c | 46 +++-- include/linux/usb/typec_mux.h | 62 +++---- 6 files changed, 242 insertions(+), 123 deletions(-) diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 6fa3cced6f8e..657b8d61554c 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -173,10 +173,10 @@ static int cht_int33fe_probe(struct platform_device *pdev) } data->connections[0].endpoint[0] = "port0"; - data->connections[0].endpoint[1] = "i2c-pi3usb30532"; + data->connections[0].endpoint[1] = "i2c-pi3usb30532-switch"; data->connections[0].id = "orientation-switch"; data->connections[1].endpoint[0] = "port0"; - data->connections[1].endpoint[1] = "i2c-pi3usb30532"; + data->connections[1].endpoint[1] = "i2c-pi3usb30532-mux"; data->connections[1].id = "mode-switch"; data->connections[2].endpoint[0] = "i2c-fusb302"; data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch"; diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h index db40e61d8b72..0c9661c96473 100644 --- a/drivers/usb/typec/bus.h +++ b/drivers/usb/typec/bus.h @@ -35,4 +35,19 @@ extern const struct device_type typec_port_dev_type; #define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type) #define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type) +extern struct class typec_mux_class; + +struct typec_switch { + struct device dev; + typec_switch_set_fn_t set; +}; + +struct typec_mux { + struct device dev; + typec_mux_set_fn_t set; +}; + +#define to_typec_switch(_dev_) container_of(_dev_, struct typec_switch, dev) +#define to_typec_mux(_dev_) container_of(_dev_, struct typec_mux, dev) + #endif /* __USB_TYPEC_ALTMODE_H__ */ diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 2eb623841847..a18285a990a8 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -1646,13 +1646,25 @@ static int __init typec_init(void) if (ret) return ret; + ret = class_register(&typec_mux_class); + if (ret) + goto err_unregister_bus; + typec_class = class_create(THIS_MODULE, "typec"); if (IS_ERR(typec_class)) { - bus_unregister(&typec_bus); - return PTR_ERR(typec_class); + ret = PTR_ERR(typec_class); + goto err_unregister_mux_class; } return 0; + +err_unregister_mux_class: + class_unregister(&typec_mux_class); + +err_unregister_bus: + bus_unregister(&typec_bus); + + return ret; } subsys_initcall(typec_init); @@ -1661,6 +1673,7 @@ static void __exit typec_exit(void) class_destroy(typec_class); ida_destroy(&typec_index_ida); bus_unregister(&typec_bus); + class_unregister(&typec_mux_class); } module_exit(typec_exit); diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index 2ce54f3fc79c..15a0e76f792c 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -15,35 +15,35 @@ #include #include -static DEFINE_MUTEX(switch_lock); -static DEFINE_MUTEX(mux_lock); -static LIST_HEAD(switch_list); -static LIST_HEAD(mux_list); +#include "bus.h" + +static int name_match(struct device *dev, const void *name) +{ + return !strcmp((const char *)name, dev_name(dev)); +} + +static int fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} static void *typec_switch_match(struct device_connection *con, int ep, void *data) { - struct typec_switch *sw; + struct device *dev; - if (!con->fwnode) { - list_for_each_entry(sw, &switch_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(sw->dev))) - return sw; - return ERR_PTR(-EPROBE_DEFER); - } + if (con->fwnode) { + if (con->id && !fwnode_property_present(con->fwnode, con->id)) + return NULL; - /* - * With OF graph the mux node must have a boolean device property named - * "orientation-switch". - */ - if (con->id && !fwnode_property_present(con->fwnode, con->id)) - return NULL; - - list_for_each_entry(sw, &switch_list, entry) - if (dev_fwnode(sw->dev) == con->fwnode) - return sw; + dev = class_find_device(&typec_mux_class, NULL, con->fwnode, + fwnode_match); + } else { + dev = class_find_device(&typec_mux_class, NULL, + con->endpoint[ep], name_match); + } - return con->id ? ERR_PTR(-EPROBE_DEFER) : NULL; + return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); } /** @@ -59,14 +59,10 @@ struct typec_switch *typec_switch_get(struct device *dev) { struct typec_switch *sw; - mutex_lock(&switch_lock); sw = device_connection_find_match(dev, "orientation-switch", NULL, typec_switch_match); - if (!IS_ERR_OR_NULL(sw)) { - WARN_ON(!try_module_get(sw->dev->driver->owner)); - get_device(sw->dev); - } - mutex_unlock(&switch_lock); + if (!IS_ERR_OR_NULL(sw)) + WARN_ON(!try_module_get(sw->dev.parent->driver->owner)); return sw; } @@ -81,28 +77,64 @@ EXPORT_SYMBOL_GPL(typec_switch_get); void typec_switch_put(struct typec_switch *sw) { if (!IS_ERR_OR_NULL(sw)) { - module_put(sw->dev->driver->owner); - put_device(sw->dev); + module_put(sw->dev.parent->driver->owner); + put_device(&sw->dev); } } EXPORT_SYMBOL_GPL(typec_switch_put); +static void typec_switch_release(struct device *dev) +{ + kfree(to_typec_switch(dev)); +} + +static const struct device_type typec_switch_dev_type = { + .name = "orientation_switch", + .release = typec_switch_release, +}; + /** * typec_switch_register - Register USB Type-C orientation switch - * @sw: USB Type-C orientation switch + * @parent: Parent device + * @desc: Orientation switch description * * This function registers a switch that can be used for routing the correct * data pairs depending on the cable plug orientation from the USB Type-C * connector to the USB controllers. USB Type-C plugs can be inserted * right-side-up or upside-down. */ -int typec_switch_register(struct typec_switch *sw) +struct typec_switch * +typec_switch_register(struct device *parent, + const struct typec_switch_desc *desc) { - mutex_lock(&switch_lock); - list_add_tail(&sw->entry, &switch_list); - mutex_unlock(&switch_lock); + struct typec_switch *sw; + int ret; + + if (!desc || !desc->set) + return ERR_PTR(-EINVAL); - return 0; + sw = kzalloc(sizeof(*sw), GFP_KERNEL); + if (!sw) + return ERR_PTR(-ENOMEM); + + sw->set = desc->set; + + device_initialize(&sw->dev); + sw->dev.parent = parent; + sw->dev.fwnode = desc->fwnode; + sw->dev.class = &typec_mux_class; + sw->dev.type = &typec_switch_dev_type; + sw->dev.driver_data = desc->drvdata; + dev_set_name(&sw->dev, "%s-switch", dev_name(parent)); + + ret = device_add(&sw->dev); + if (ret) { + dev_err(parent, "failed to register switch (%d)\n", ret); + put_device(&sw->dev); + return ERR_PTR(ret); + } + + return sw; } EXPORT_SYMBOL_GPL(typec_switch_register); @@ -114,28 +146,39 @@ EXPORT_SYMBOL_GPL(typec_switch_register); */ void typec_switch_unregister(struct typec_switch *sw) { - mutex_lock(&switch_lock); - list_del(&sw->entry); - mutex_unlock(&switch_lock); + if (!IS_ERR_OR_NULL(sw)) + device_unregister(&sw->dev); } EXPORT_SYMBOL_GPL(typec_switch_unregister); +void typec_switch_set_drvdata(struct typec_switch *sw, void *data) +{ + dev_set_drvdata(&sw->dev, data); +} +EXPORT_SYMBOL_GPL(typec_switch_set_drvdata); + +void *typec_switch_get_drvdata(struct typec_switch *sw) +{ + return dev_get_drvdata(&sw->dev); +} +EXPORT_SYMBOL_GPL(typec_switch_get_drvdata); + /* ------------------------------------------------------------------------- */ static void *typec_mux_match(struct device_connection *con, int ep, void *data) { const struct typec_altmode_desc *desc = data; - struct typec_mux *mux; - int nval; + struct device *dev; bool match; + int nval; u16 *val; int i; if (!con->fwnode) { - list_for_each_entry(mux, &mux_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(mux->dev))) - return mux; - return ERR_PTR(-EPROBE_DEFER); + dev = class_find_device(&typec_mux_class, NULL, + con->endpoint[ep], name_match); + + return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); } /* @@ -180,11 +223,10 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data) return NULL; find_mux: - list_for_each_entry(mux, &mux_list, entry) - if (dev_fwnode(mux->dev) == con->fwnode) - return mux; + dev = class_find_device(&typec_mux_class, NULL, con->fwnode, + fwnode_match); - return ERR_PTR(-EPROBE_DEFER); + return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); } /** @@ -202,14 +244,10 @@ struct typec_mux *typec_mux_get(struct device *dev, { struct typec_mux *mux; - mutex_lock(&mux_lock); mux = device_connection_find_match(dev, "mode-switch", (void *)desc, typec_mux_match); - if (!IS_ERR_OR_NULL(mux)) { - WARN_ON(!try_module_get(mux->dev->driver->owner)); - get_device(mux->dev); - } - mutex_unlock(&mux_lock); + if (!IS_ERR_OR_NULL(mux)) + WARN_ON(!try_module_get(mux->dev.parent->driver->owner)); return mux; } @@ -224,28 +262,63 @@ EXPORT_SYMBOL_GPL(typec_mux_get); void typec_mux_put(struct typec_mux *mux) { if (!IS_ERR_OR_NULL(mux)) { - module_put(mux->dev->driver->owner); - put_device(mux->dev); + module_put(mux->dev.parent->driver->owner); + put_device(&mux->dev); } } EXPORT_SYMBOL_GPL(typec_mux_put); +static void typec_mux_release(struct device *dev) +{ + kfree(to_typec_mux(dev)); +} + +static const struct device_type typec_mux_dev_type = { + .name = "mode_switch", + .release = typec_mux_release, +}; + /** * typec_mux_register - Register Multiplexer routing USB Type-C pins - * @mux: USB Type-C Connector Multiplexer/DeMultiplexer + * @parent: Parent device + * @desc: Multiplexer description * * USB Type-C connectors can be used for alternate modes of operation besides * USB when Accessory/Alternate Modes are supported. With some of those modes, * the pins on the connector need to be reconfigured. This function registers * multiplexer switches routing the pins on the connector. */ -int typec_mux_register(struct typec_mux *mux) +struct typec_mux * +typec_mux_register(struct device *parent, const struct typec_mux_desc *desc) { - mutex_lock(&mux_lock); - list_add_tail(&mux->entry, &mux_list); - mutex_unlock(&mux_lock); + struct typec_mux *mux; + int ret; + + if (!desc || !desc->set) + return ERR_PTR(-EINVAL); + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); - return 0; + mux->set = desc->set; + + device_initialize(&mux->dev); + mux->dev.parent = parent; + mux->dev.fwnode = desc->fwnode; + mux->dev.class = &typec_mux_class; + mux->dev.type = &typec_mux_dev_type; + mux->dev.driver_data = desc->drvdata; + dev_set_name(&mux->dev, "%s-mux", dev_name(parent)); + + ret = device_add(&mux->dev); + if (ret) { + dev_err(parent, "failed to register mux (%d)\n", ret); + put_device(&mux->dev); + return ERR_PTR(ret); + } + + return mux; } EXPORT_SYMBOL_GPL(typec_mux_register); @@ -257,8 +330,24 @@ EXPORT_SYMBOL_GPL(typec_mux_register); */ void typec_mux_unregister(struct typec_mux *mux) { - mutex_lock(&mux_lock); - list_del(&mux->entry); - mutex_unlock(&mux_lock); + if (!IS_ERR_OR_NULL(mux)) + device_unregister(&mux->dev); } EXPORT_SYMBOL_GPL(typec_mux_unregister); + +void typec_mux_set_drvdata(struct typec_mux *mux, void *data) +{ + dev_set_drvdata(&mux->dev, data); +} +EXPORT_SYMBOL_GPL(typec_mux_set_drvdata); + +void *typec_mux_get_drvdata(struct typec_mux *mux) +{ + return dev_get_drvdata(&mux->dev); +} +EXPORT_SYMBOL_GPL(typec_mux_get_drvdata); + +struct class typec_mux_class = { + .name = "typec_mux", + .owner = THIS_MODULE, +}; diff --git a/drivers/usb/typec/mux/pi3usb30532.c b/drivers/usb/typec/mux/pi3usb30532.c index 9294e85fd34b..5585b109095b 100644 --- a/drivers/usb/typec/mux/pi3usb30532.c +++ b/drivers/usb/typec/mux/pi3usb30532.c @@ -23,8 +23,8 @@ struct pi3usb30532 { struct i2c_client *client; struct mutex lock; /* protects the cached conf register */ - struct typec_switch sw; - struct typec_mux mux; + struct typec_switch *sw; + struct typec_mux *mux; u8 conf; }; @@ -48,7 +48,7 @@ static int pi3usb30532_set_conf(struct pi3usb30532 *pi, u8 new_conf) static int pi3usb30532_sw_set(struct typec_switch *sw, enum typec_orientation orientation) { - struct pi3usb30532 *pi = container_of(sw, struct pi3usb30532, sw); + struct pi3usb30532 *pi = typec_switch_get_drvdata(sw); u8 new_conf; int ret; @@ -75,7 +75,7 @@ static int pi3usb30532_sw_set(struct typec_switch *sw, static int pi3usb30532_mux_set(struct typec_mux *mux, int state) { - struct pi3usb30532 *pi = container_of(mux, struct pi3usb30532, mux); + struct pi3usb30532 *pi = typec_mux_get_drvdata(mux); u8 new_conf; int ret; @@ -113,6 +113,8 @@ static int pi3usb30532_mux_set(struct typec_mux *mux, int state) static int pi3usb30532_probe(struct i2c_client *client) { struct device *dev = &client->dev; + struct typec_switch_desc sw_desc; + struct typec_mux_desc mux_desc; struct pi3usb30532 *pi; int ret; @@ -121,10 +123,6 @@ static int pi3usb30532_probe(struct i2c_client *client) return -ENOMEM; pi->client = client; - pi->sw.dev = dev; - pi->sw.set = pi3usb30532_sw_set; - pi->mux.dev = dev; - pi->mux.set = pi3usb30532_mux_set; mutex_init(&pi->lock); ret = i2c_smbus_read_byte_data(client, PI3USB30532_CONF); @@ -134,17 +132,27 @@ static int pi3usb30532_probe(struct i2c_client *client) } pi->conf = ret; - ret = typec_switch_register(&pi->sw); - if (ret) { - dev_err(dev, "Error registering typec switch: %d\n", ret); - return ret; + sw_desc.drvdata = pi; + sw_desc.fwnode = dev->fwnode; + sw_desc.set = pi3usb30532_sw_set; + + pi->sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(pi->sw)) { + dev_err(dev, "Error registering typec switch: %ld\n", + PTR_ERR(pi->sw)); + return PTR_ERR(pi->sw); } - ret = typec_mux_register(&pi->mux); - if (ret) { - typec_switch_unregister(&pi->sw); - dev_err(dev, "Error registering typec mux: %d\n", ret); - return ret; + mux_desc.drvdata = pi; + mux_desc.fwnode = dev->fwnode; + mux_desc.set = pi3usb30532_mux_set; + + pi->mux = typec_mux_register(dev, &mux_desc); + if (IS_ERR(pi->mux)) { + typec_switch_unregister(pi->sw); + dev_err(dev, "Error registering typec mux: %ld\n", + PTR_ERR(pi->mux)); + return PTR_ERR(pi->mux); } i2c_set_clientdata(client, pi); @@ -155,8 +163,8 @@ static int pi3usb30532_remove(struct i2c_client *client) { struct pi3usb30532 *pi = i2c_get_clientdata(client); - typec_mux_unregister(&pi->mux); - typec_switch_unregister(&pi->sw); + typec_mux_unregister(pi->mux); + typec_switch_unregister(pi->sw); return 0; } diff --git a/include/linux/usb/typec_mux.h b/include/linux/usb/typec_mux.h index 43f40685e53c..873ace5b0cf8 100644 --- a/include/linux/usb/typec_mux.h +++ b/include/linux/usb/typec_mux.h @@ -3,54 +3,48 @@ #ifndef __USB_TYPEC_MUX #define __USB_TYPEC_MUX -#include #include struct device; +struct typec_mux; +struct typec_switch; +struct fwnode_handle; -/** - * struct typec_switch - USB Type-C cable orientation switch - * @dev: Switch device - * @entry: List entry - * @set: Callback to the driver for setting the orientation - * - * USB Type-C pin flipper switch routing the correct data pairs from the - * connector to the USB controller depending on the orientation of the cable - * plug. - */ -struct typec_switch { - struct device *dev; - struct list_head entry; - - int (*set)(struct typec_switch *sw, enum typec_orientation orientation); -}; +typedef int (*typec_switch_set_fn_t)(struct typec_switch *sw, + enum typec_orientation orientation); -/** - * struct typec_switch - USB Type-C connector pin mux - * @dev: Mux device - * @entry: List entry - * @set: Callback to the driver for setting the state of the mux - * - * Pin Multiplexer/DeMultiplexer switch routing the USB Type-C connector pins to - * different components depending on the requested mode of operation. Used with - * Accessory/Alternate modes. - */ -struct typec_mux { - struct device *dev; - struct list_head entry; - - int (*set)(struct typec_mux *mux, int state); +struct typec_switch_desc { + struct fwnode_handle *fwnode; + typec_switch_set_fn_t set; + void *drvdata; }; struct typec_switch *typec_switch_get(struct device *dev); void typec_switch_put(struct typec_switch *sw); -int typec_switch_register(struct typec_switch *sw); +struct typec_switch * +typec_switch_register(struct device *parent, + const struct typec_switch_desc *desc); void typec_switch_unregister(struct typec_switch *sw); +void typec_switch_set_drvdata(struct typec_switch *sw, void *data); +void *typec_switch_get_drvdata(struct typec_switch *sw); + +typedef int (*typec_mux_set_fn_t)(struct typec_mux *mux, int state); + +struct typec_mux_desc { + struct fwnode_handle *fwnode; + typec_mux_set_fn_t set; + void *drvdata; +}; + struct typec_mux * typec_mux_get(struct device *dev, const struct typec_altmode_desc *desc); void typec_mux_put(struct typec_mux *mux); -int typec_mux_register(struct typec_mux *mux); +struct typec_mux * +typec_mux_register(struct device *parent, const struct typec_mux_desc *desc); void typec_mux_unregister(struct typec_mux *mux); +void typec_mux_set_drvdata(struct typec_mux *mux, void *data); +void *typec_mux_get_drvdata(struct typec_mux *mux); + #endif /* __USB_TYPEC_MUX */ From patchwork Wed Apr 3 16:45:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884203 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 528041390 for ; Wed, 3 Apr 2019 16:46:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3C4CB2522B for ; Wed, 3 Apr 2019 16:46:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3050628990; Wed, 3 Apr 2019 16:46:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9F6732522B for ; Wed, 3 Apr 2019 16:46:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728931AbfDCQqD (ORCPT ); Wed, 3 Apr 2019 12:46:03 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728926AbfDCQqD (ORCPT ); Wed, 3 Apr 2019 12:46:03 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:46:02 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077458" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:46:00 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 08/11] platform/x86: intel_cht_int33fe: Provide software nodes for the devices Date: Wed, 3 Apr 2019 19:45:34 +0300 Message-Id: <20190403164537.24643-9-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Software nodes provide two features that we will need later. 1) Software nodes can have references to other software nodes. 2) Software nodes can exist before a device entry is created. Signed-off-by: Heikki Krogerus --- drivers/platform/x86/intel_cht_int33fe.c | 122 +++++++++++++++++------ 1 file changed, 92 insertions(+), 30 deletions(-) diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 657b8d61554c..2f12ce154489 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -24,15 +24,25 @@ #include #include #include +#include #define EXPECTED_PTYPE 4 +enum { + INT33FE_NODE_FUSB302, + INT33FE_NODE_MAX17047, + INT33FE_NODE_PI3USB30532, + INT33FE_NODE_MAX, +}; + struct cht_int33fe_data { struct i2c_client *max17047; struct i2c_client *fusb302; struct i2c_client *pi3usb30532; /* Contain a list-head must be per device */ struct device_connection connections[4]; + + struct fwnode_handle *node[INT33FE_NODE_MAX]; }; /* @@ -63,14 +73,6 @@ static int cht_int33fe_check_for_max17047(struct device *dev, void *data) return 1; } -static struct i2c_client *cht_int33fe_find_max17047(void) -{ - struct i2c_client *max17047 = NULL; - - i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047); - return max17047; -} - static const char * const max17047_suppliers[] = { "bq24190-charger" }; static const struct property_entry max17047_props[] = { @@ -78,6 +80,36 @@ static const struct property_entry max17047_props[] = { { } }; +static int +cht_int33fe_max17047(struct device *dev, struct cht_int33fe_data *data) +{ + struct fwnode_handle *fwnode = data->node[INT33FE_NODE_MAX17047]; + struct i2c_client *max17047 = NULL; + struct i2c_board_info board_info; + int ret; + + i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047); + if (max17047) { + /* Pre-existing i2c-client for the max17047, add device-props */ + max17047->dev.fwnode->secondary = fwnode; + /* And re-probe to get the new device-props applied. */ + ret = device_reprobe(&max17047->dev); + if (ret) + dev_warn(dev, "Reprobing max17047 error: %d\n", ret); + return 0; + } + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); + board_info.dev_name = "max17047"; + board_info.fwnode = fwnode; + data->max17047 = i2c_acpi_new_device(dev, 1, &board_info); + if (IS_ERR(data->max17047)) + return PTR_ERR(data->max17047); + + return 0; +} + static const struct property_entry fusb302_props[] = { PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"), PROPERTY_ENTRY_U32("fcs,max-sink-microvolt", 12000000), @@ -86,12 +118,50 @@ static const struct property_entry fusb302_props[] = { { } }; +static const struct property_entry *props[] = { + [INT33FE_NODE_FUSB302] = fusb302_props, + [INT33FE_NODE_MAX17047] = max17047_props, + [INT33FE_NODE_PI3USB30532] = NULL, +}; + +static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data) +{ + int i; + + for (i = 0; i < INT33FE_NODE_MAX; i++) { + fwnode_remove_software_node(data->node[i]); + data->node[i] = NULL; + } +} + +static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) +{ + struct fwnode_handle *fwnode; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(props); i++) { + fwnode = fwnode_create_software_node(props[i], NULL); + if (IS_ERR(fwnode)) { + ret = PTR_ERR(fwnode); + goto err_remove_nodes; + } + data->node[i] = fwnode; + } + + return 0; + +err_remove_nodes: + cht_int33fe_remove_nodes(data); + + return ret; +} + static int cht_int33fe_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct i2c_board_info board_info; struct cht_int33fe_data *data; - struct i2c_client *max17047; struct regulator *regulator; unsigned long long ptyp; acpi_status status; @@ -151,26 +221,14 @@ static int cht_int33fe_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + ret = cht_int33fe_add_nodes(data); + if (ret) + return ret; + /* Work around BIOS bug, see comment on cht_int33fe_find_max17047 */ - max17047 = cht_int33fe_find_max17047(); - if (max17047) { - /* Pre-existing i2c-client for the max17047, add device-props */ - ret = device_add_properties(&max17047->dev, max17047_props); - if (ret) - return ret; - /* And re-probe to get the new device-props applied. */ - ret = device_reprobe(&max17047->dev); - if (ret) - dev_warn(dev, "Reprobing max17047 error: %d\n", ret); - } else { - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); - board_info.dev_name = "max17047"; - board_info.properties = max17047_props; - data->max17047 = i2c_acpi_new_device(dev, 1, &board_info); - if (IS_ERR(data->max17047)) - return PTR_ERR(data->max17047); - } + ret = cht_int33fe_max17047(dev, data); + if (ret) + goto out_remove_nodes; data->connections[0].endpoint[0] = "port0"; data->connections[0].endpoint[1] = "i2c-pi3usb30532-switch"; @@ -187,7 +245,7 @@ static int cht_int33fe_probe(struct platform_device *pdev) memset(&board_info, 0, sizeof(board_info)); strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); board_info.dev_name = "fusb302"; - board_info.properties = fusb302_props; + board_info.fwnode = data->node[INT33FE_NODE_FUSB302]; board_info.irq = fusb302_irq; data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info); @@ -198,6 +256,7 @@ static int cht_int33fe_probe(struct platform_device *pdev) memset(&board_info, 0, sizeof(board_info)); board_info.dev_name = "pi3usb30532"; + board_info.fwnode = data->node[INT33FE_NODE_PI3USB30532]; strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE); data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info); @@ -214,9 +273,11 @@ static int cht_int33fe_probe(struct platform_device *pdev) i2c_unregister_device(data->fusb302); out_unregister_max17047: + device_connections_remove(data->connections); i2c_unregister_device(data->max17047); - device_connections_remove(data->connections); +out_remove_nodes: + cht_int33fe_remove_nodes(data); return ret; } @@ -230,6 +291,7 @@ static int cht_int33fe_remove(struct platform_device *pdev) i2c_unregister_device(data->max17047); device_connections_remove(data->connections); + cht_int33fe_remove_nodes(data); return 0; } From patchwork Wed Apr 3 16:45:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884201 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EE54117E0 for ; Wed, 3 Apr 2019 16:46:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DC8E22522B for ; Wed, 3 Apr 2019 16:46:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CE6FE28990; Wed, 3 Apr 2019 16:46:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 693272522B for ; Wed, 3 Apr 2019 16:46:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726084AbfDCQqH (ORCPT ); Wed, 3 Apr 2019 12:46:07 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726168AbfDCQqG (ORCPT ); Wed, 3 Apr 2019 12:46:06 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:46:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077479" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:46:02 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 09/11] platform/x86: intel_cht_int33fe: Provide fwnode for the USB connector Date: Wed, 3 Apr 2019 19:45:35 +0300 Message-Id: <20190403164537.24643-10-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP In ACPI, and now also in DT, the USB connectors usually have their own device nodes. In case of USB Type-C, those connector (port) nodes are child nodes of the controller or PHY device, in our case the fusb302. The software fwnodes allow us to create a similar child node for fusb302 that represents the connector also on Intel CHT. This makes it possible replace the fusb302 specific device properties which were deprecated with the common USB connector properties that tcpm.c is able to use directly. Signed-off-by: Heikki Krogerus Reviewed-by: Andy Shevchenko --- drivers/platform/x86/intel_cht_int33fe.c | 37 ++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 2f12ce154489..544e0b90aa07 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -25,6 +25,7 @@ #include #include #include +#include #define EXPECTED_PTYPE 4 @@ -32,6 +33,7 @@ enum { INT33FE_NODE_FUSB302, INT33FE_NODE_MAX17047, INT33FE_NODE_PI3USB30532, + INT33FE_NODE_USB_CONNECTOR, INT33FE_NODE_MAX, }; @@ -112,9 +114,29 @@ cht_int33fe_max17047(struct device *dev, struct cht_int33fe_data *data) static const struct property_entry fusb302_props[] = { PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"), - PROPERTY_ENTRY_U32("fcs,max-sink-microvolt", 12000000), - PROPERTY_ENTRY_U32("fcs,max-sink-microamp", 3000000), - PROPERTY_ENTRY_U32("fcs,max-sink-microwatt", 36000000), + { } +}; + +#define PDO_FIXED_FLAGS \ + (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP | PDO_FIXED_USB_COMM) + +static const u32 src_pdo[] = { + PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS), +}; + +static const u32 snk_pdo[] = { + PDO_FIXED(5000, 400, PDO_FIXED_FLAGS), + PDO_VAR(5000, 12000, 3000), +}; + +static const struct property_entry usb_connector_props[] = { + PROPERTY_ENTRY_STRING("name", "connector"), + PROPERTY_ENTRY_STRING("data-role", "dual"), + PROPERTY_ENTRY_STRING("power-role", "dual"), + PROPERTY_ENTRY_STRING("try-power-role", "sink"), + PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo), + PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo), + PROPERTY_ENTRY_U32("op-sink-microwatt", 36000000), { } }; @@ -149,6 +171,15 @@ static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) data->node[i] = fwnode; } + /* Node for the USB connector (FUSB302 is the parent) */ + fwnode = fwnode_create_software_node(usb_connector_props, + data->node[INT33FE_NODE_FUSB302]); + if (IS_ERR(fwnode)) { + ret = PTR_ERR(fwnode); + goto err_remove_nodes; + } + data->node[INT33FE_NODE_USB_CONNECTOR] = fwnode; + return 0; err_remove_nodes: From patchwork Wed Apr 3 16:45:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884195 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CFAF11390 for ; Wed, 3 Apr 2019 16:46:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B862C27FA8 for ; Wed, 3 Apr 2019 16:46:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ACAD828990; Wed, 3 Apr 2019 16:46:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3A29127FA8 for ; Wed, 3 Apr 2019 16:46:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726930AbfDCQqK (ORCPT ); Wed, 3 Apr 2019 12:46:10 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728942AbfDCQqI (ORCPT ); Wed, 3 Apr 2019 12:46:08 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:46:07 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077483" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:46:05 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 10/11] platform/x86: intel_cht_int33fe: Link with external dependencies using fwnodes Date: Wed, 3 Apr 2019 19:45:36 +0300 Message-Id: <20190403164537.24643-11-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Supplying also external devices - the DisplayPort connector and the USB role switch - software fwnodes. After this the driver has access to all the components tied to the USB Type-C connector and can start creating software node references to actually associate them with the USB Type-C connector device. Signed-off-by: Heikki Krogerus --- drivers/platform/x86/intel_cht_int33fe.c | 99 ++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 544e0b90aa07..ed21aeacec24 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -33,6 +33,8 @@ enum { INT33FE_NODE_FUSB302, INT33FE_NODE_MAX17047, INT33FE_NODE_PI3USB30532, + INT33FE_NODE_DISPLAYPORT, + INT33FE_NODE_ROLE_SWITCH, INT33FE_NODE_USB_CONNECTOR, INT33FE_NODE_MAX, }; @@ -44,6 +46,7 @@ struct cht_int33fe_data { /* Contain a list-head must be per device */ struct device_connection connections[4]; + struct fwnode_handle *dp; struct fwnode_handle *node[INT33FE_NODE_MAX]; }; @@ -144,8 +147,78 @@ static const struct property_entry *props[] = { [INT33FE_NODE_FUSB302] = fusb302_props, [INT33FE_NODE_MAX17047] = max17047_props, [INT33FE_NODE_PI3USB30532] = NULL, + [INT33FE_NODE_DISPLAYPORT] = NULL, + [INT33FE_NODE_ROLE_SWITCH] = NULL, }; +static int role_switch_match(struct device *dev, void *name) +{ + return !strcmp(dev_name(dev), name); +} + +static int cht_int33fe_setup_mux(struct cht_int33fe_data *data) +{ + struct fwnode_handle *fwnode = data->node[INT33FE_NODE_ROLE_SWITCH]; + struct pci_dev *pdev; + struct device *dev; + struct device *p; + + /* First let's find xHCI PCI device */ + pdev = pci_get_class(PCI_CLASS_SERIAL_USB_XHCI, NULL); + if (!pdev || (pdev->vendor != PCI_VENDOR_ID_INTEL)) + return -ENODEV; + + /* Then the child platform device */ + p = device_find_child(&pdev->dev, "intel_xhci_usb_sw", + role_switch_match); + pci_dev_put(pdev); + if (!p) + return -EPROBE_DEFER; + + /* Finally the mux device */ + dev = device_find_child(p, "intel_xhci_usb_sw-role-switch", + role_switch_match); + put_device(p); + if (!dev) + return -EPROBE_DEFER; + + /* If there already is a node for the mux, using that one. */ + if (dev->fwnode) { + fwnode_handle_get(dev->fwnode); + fwnode_remove_software_node(fwnode); + data->node[INT33FE_NODE_ROLE_SWITCH] = dev->fwnode; + } else { + /* The node can be tied to the lifetime of the device. */ + dev->fwnode = fwnode_handle_get(dev->fwnode); + } + + put_device(dev); + + return 0; +} + +static int cht_int33fe_setup_dp(struct cht_int33fe_data *data) +{ + struct fwnode_handle *fwnode = data->node[INT33FE_NODE_DISPLAYPORT]; + struct pci_dev *pdev; + + /* First let's find the GPU PCI device */ + pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); + if (!pdev || (pdev->vendor != PCI_VENDOR_ID_INTEL)) + return -ENODEV; + + /* Then the DP child device node */ + data->dp = device_get_named_child_node(&pdev->dev, "DD02"); + pci_dev_put(pdev); + if (!data->dp) + return -ENODEV; + + fwnode->secondary = ERR_PTR(-ENODEV); + data->dp->secondary = fwnode; + + return 0; +} + static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data) { int i; @@ -154,6 +227,12 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data) fwnode_remove_software_node(data->node[i]); data->node[i] = NULL; } + + if (data->dp) { + data->dp->secondary = NULL; + fwnode_handle_put(data->dp); + data->dp = NULL; + } } static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) @@ -180,6 +259,26 @@ static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) } data->node[INT33FE_NODE_USB_CONNECTOR] = fwnode; + /* The devices that are not created in this driver need extra steps. */ + + /* + * There is no ACPI device node for the USB role mux, so we need to find + * the mux device and assign our node directly to it. That means we + * depend on the mux driver. This function will return -PROBE_DEFER + * until the mux device is registered. + */ + ret = cht_int33fe_setup_mux(data); + if (ret) + goto err_remove_nodes; + + /* + * The DP connector does have ACPI device node. In this case we can just + * find that ACPI node and assing our node as the secondary node to it. + */ + ret = cht_int33fe_setup_dp(data); + if (ret) + goto err_remove_nodes; + return 0; err_remove_nodes: From patchwork Wed Apr 3 16:45:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 10884191 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 40C0917E0 for ; Wed, 3 Apr 2019 16:46:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2B4FD2522B for ; Wed, 3 Apr 2019 16:46:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1FA0F289C6; Wed, 3 Apr 2019 16:46:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8E1052522B for ; Wed, 3 Apr 2019 16:46:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728683AbfDCQqY (ORCPT ); Wed, 3 Apr 2019 12:46:24 -0400 Received: from mga11.intel.com ([192.55.52.93]:21215 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726168AbfDCQqK (ORCPT ); Wed, 3 Apr 2019 12:46:10 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Apr 2019 09:46:10 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,305,1549958400"; d="scan'208";a="161077490" Received: from black.fi.intel.com (HELO black.fi.intel.com.) ([10.237.72.28]) by fmsmga001.fm.intel.com with ESMTP; 03 Apr 2019 09:46:07 -0700 From: Heikki Krogerus To: "Rafael J. Wysocki" , Greg Kroah-Hartman , Hans de Goede Cc: Darren Hart , Andy Shevchenko , linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org Subject: [PATCH 11/11] platform/x86: intel_cht_int33fe: Replacing the old connections with references Date: Wed, 3 Apr 2019 19:45:37 +0300 Message-Id: <20190403164537.24643-12-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> References: <20190403164537.24643-1-heikki.krogerus@linux.intel.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Now that the software nodes support references, and the device connection API support parsing fwnode references, replacing the old connection descriptions with software node references. Relying on device names when matching the connection would not have been possible to link the USB Type-C connector and the DisplayPort connector together, but with real references it's not problem. The DisplayPort ACPI node is dag up, and the drivers own software node for the DisplayPort is set as the secondary node for it. The USB Type-C connector refers the software node, but it is now tied to the ACPI node, and therefore any device entry (struct drm_connector in practice) that the node combo is assigned to. The USB role switch device does not have ACPI node, so we have to wait for the device to appear. Then we can simply assign our software node for the to the device. Signed-off-by: Heikki Krogerus Reviewed-by: Andy Shevchenko --- drivers/platform/x86/intel_cht_int33fe.c | 94 +++++++++++++++++++----- 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index ed21aeacec24..f0844a04299b 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -39,15 +39,22 @@ enum { INT33FE_NODE_MAX, }; +enum { + INT33FE_REF_ORIENTATION, + INT33FE_REF_MODE_MUX, + INT33FE_REF_DISPLAYPORT, + INT33FE_REF_ROLE_SWITCH, + INT33FE_REF_MAX, +}; + struct cht_int33fe_data { struct i2c_client *max17047; struct i2c_client *fusb302; struct i2c_client *pi3usb30532; - /* Contain a list-head must be per device */ - struct device_connection connections[4]; struct fwnode_handle *dp; struct fwnode_handle *node[INT33FE_NODE_MAX]; + struct software_node_reference *ref[INT33FE_REF_MAX]; }; /* @@ -287,6 +294,65 @@ static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) return ret; } +static void cht_int33fe_remove_references(struct cht_int33fe_data *data) +{ + int i; + + for (i = 0; i < INT33FE_REF_MAX; i++) + fwnode_remove_software_node_reference(data->ref[i]); +} + +static int cht_int33fe_add_references(struct cht_int33fe_data *data) +{ + struct fwnode_reference_args args[2] = { }; + struct software_node_reference *ref; + struct fwnode_handle *con; + + con = data->node[INT33FE_NODE_USB_CONNECTOR]; + + /* USB Type-C muxes */ + args[0].fwnode = data->node[INT33FE_NODE_PI3USB30532]; + args[1].fwnode = NULL; + + ref = fwnode_create_software_node_reference(con, "orientation-switch", + args); + if (IS_ERR(ref)) + return PTR_ERR(ref); + data->ref[INT33FE_REF_ORIENTATION] = ref; + + ref = fwnode_create_software_node_reference(con, "mode-switch", args); + if (IS_ERR(ref)) { + cht_int33fe_remove_references(data); + return PTR_ERR(ref); + } + data->ref[INT33FE_REF_MODE_MUX] = ref; + + /* USB role switch */ + args[0].fwnode = data->node[INT33FE_NODE_ROLE_SWITCH]; + args[1].fwnode = NULL; + + ref = fwnode_create_software_node_reference(con, "usb-role-switch", + args); + if (IS_ERR(ref)) { + cht_int33fe_remove_references(data); + return PTR_ERR(ref); + } + data->ref[INT33FE_REF_ROLE_SWITCH] = ref; + + /* DisplayPort */ + args[0].fwnode = data->node[INT33FE_NODE_DISPLAYPORT]; + args[1].fwnode = NULL; + + ref = fwnode_create_software_node_reference(con, "displayport", args); + if (IS_ERR(ref)) { + cht_int33fe_remove_references(data); + return PTR_ERR(ref); + } + data->ref[INT33FE_REF_DISPLAYPORT] = ref; + + return 0; +} + static int cht_int33fe_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -355,22 +421,14 @@ static int cht_int33fe_probe(struct platform_device *pdev) if (ret) return ret; - /* Work around BIOS bug, see comment on cht_int33fe_find_max17047 */ - ret = cht_int33fe_max17047(dev, data); + ret = cht_int33fe_add_references(data); if (ret) goto out_remove_nodes; - data->connections[0].endpoint[0] = "port0"; - data->connections[0].endpoint[1] = "i2c-pi3usb30532-switch"; - data->connections[0].id = "orientation-switch"; - data->connections[1].endpoint[0] = "port0"; - data->connections[1].endpoint[1] = "i2c-pi3usb30532-mux"; - data->connections[1].id = "mode-switch"; - data->connections[2].endpoint[0] = "i2c-fusb302"; - data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch"; - data->connections[2].id = "usb-role-switch"; - - device_connections_add(data->connections); + /* Work around BIOS bug, see comment on cht_int33fe_find_max17047 */ + ret = cht_int33fe_max17047(dev, data); + if (ret) + goto out_remove_references; memset(&board_info, 0, sizeof(board_info)); strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); @@ -403,9 +461,11 @@ static int cht_int33fe_probe(struct platform_device *pdev) i2c_unregister_device(data->fusb302); out_unregister_max17047: - device_connections_remove(data->connections); i2c_unregister_device(data->max17047); +out_remove_references: + cht_int33fe_remove_references(data); + out_remove_nodes: cht_int33fe_remove_nodes(data); @@ -420,7 +480,7 @@ static int cht_int33fe_remove(struct platform_device *pdev) i2c_unregister_device(data->fusb302); i2c_unregister_device(data->max17047); - device_connections_remove(data->connections); + cht_int33fe_remove_references(data); cht_int33fe_remove_nodes(data); return 0;