From patchwork Wed Jun 12 08:36:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolaus Voss X-Patchwork-Id: 10988963 X-Patchwork-Delegate: rjw@sisk.pl 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 5AD8313AF for ; Wed, 12 Jun 2019 08:36:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 49394289B9 for ; Wed, 12 Jun 2019 08:36:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3D760289C2; Wed, 12 Jun 2019 08:36:43 +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 50FAC289B9 for ; Wed, 12 Jun 2019 08:36:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727241AbfFLIgk (ORCPT ); Wed, 12 Jun 2019 04:36:40 -0400 Received: from mail.steuer-voss.de ([85.183.69.95]:43430 "EHLO mail.steuer-voss.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725962AbfFLIgk (ORCPT ); Wed, 12 Jun 2019 04:36:40 -0400 Received: from pc-niv.weinmann.com (localhost [127.0.0.1]) by mail.steuer-voss.de (Postfix) with ESMTP id 80C9B4D05C; Wed, 12 Jun 2019 10:36:37 +0200 (CEST) From: Nikolaus Voss To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Erik Schmauss , Jacek Anaszewski , Pavel Machek , Dan Murphy , Thierry Reding Cc: Nikolaus Voss , linux-acpi@vger.kernel.org, devel@acpica.org, linux-leds@vger.kernel.org, linux-pwm@vger.kernel.org, linux-kernel@vger.kernel.org, nv@vosn.de Subject: [PATCH v2 1/3] ACPI: Resolve objects on host-directed table loads Date: Wed, 12 Jun 2019 10:36:06 +0200 Message-Id: X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP If an ACPI SSDT overlay is loaded after built-in tables have been loaded e.g. via configfs or efivar_ssdt_load() it is necessary to rewalk the namespace to resolve references. Without this, relative and absolute paths like ^PCI0.SBUS or \_SB.PCI0.SBUS are not resolved correctly. Make configfs load use the same method as efivar_ssdt_load(). Signed-off-by: Nikolaus Voss Acked-by: Rafael J. Wysocki --- drivers/acpi/acpi_configfs.c | 6 +----- drivers/acpi/acpica/tbxfload.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/acpi_configfs.c b/drivers/acpi/acpi_configfs.c index f92033661239..663f0d88f912 100644 --- a/drivers/acpi/acpi_configfs.c +++ b/drivers/acpi/acpi_configfs.c @@ -56,11 +56,7 @@ static ssize_t acpi_table_aml_write(struct config_item *cfg, if (!table->header) return -ENOMEM; - ACPI_INFO(("Host-directed Dynamic ACPI Table Load:")); - ret = acpi_tb_install_and_load_table( - ACPI_PTR_TO_PHYSADDR(table->header), - ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, FALSE, - &table->index); + ret = acpi_load_table(table->header); if (ret) { kfree(table->header); table->header = NULL; diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 4f30f06a6f78..ef8f8a9f3c9c 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -297,6 +297,17 @@ acpi_status acpi_load_table(struct acpi_table_header *table) status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table), ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, FALSE, &table_index); + + if (ACPI_SUCCESS(status)) { + /* Complete the initialization/resolution of package objects */ + + status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE, + ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, 0, + acpi_ns_init_one_package, + NULL, NULL, NULL); + } + return_ACPI_STATUS(status); } From patchwork Wed Jun 12 08:36:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolaus Voss X-Patchwork-Id: 10988961 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 90A621708 for ; Wed, 12 Jun 2019 08:36:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7DFBC289BA for ; Wed, 12 Jun 2019 08:36:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 719D3289C4; Wed, 12 Jun 2019 08:36:42 +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 CEB53289BA for ; Wed, 12 Jun 2019 08:36:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729217AbfFLIgl (ORCPT ); Wed, 12 Jun 2019 04:36:41 -0400 Received: from mail.steuer-voss.de ([85.183.69.95]:43446 "EHLO mail.steuer-voss.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726778AbfFLIgk (ORCPT ); Wed, 12 Jun 2019 04:36:40 -0400 Received: from pc-niv.weinmann.com (localhost [127.0.0.1]) by mail.steuer-voss.de (Postfix) with ESMTP id 5473B4D07F; Wed, 12 Jun 2019 10:36:38 +0200 (CEST) From: Nikolaus Voss To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Erik Schmauss , Jacek Anaszewski , Pavel Machek , Dan Murphy , Thierry Reding Cc: Nikolaus Voss , linux-acpi@vger.kernel.org, devel@acpica.org, linux-leds@vger.kernel.org, linux-pwm@vger.kernel.org, linux-kernel@vger.kernel.org, nv@vosn.de Subject: [PATCH v2 2/3] PWM framework: add support referencing PWMs from ACPI Date: Wed, 12 Jun 2019 10:36:07 +0200 Message-Id: <68c51a7af257b5c6d4f7d1b95b181b920132a64d.1560327219.git.nikolaus.voss@loewensteinmedical.de> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP In analogy to referencing a GPIO using the "gpios" property from ACPI, support referencing a PWM using the "pwms" property. ACPI entries must look like Package () {"pwms", Package () { , , [, ]}} In contrast to the DT implementation, only _one_ PWM entry in the "pwms" property is supported. As a consequence "pwm-names"-property and con_id lookup aren't supported. Support for ACPI is added via the firmware-node framework which is an abstraction layer on top of ACPI/DT. To keep this patch clean, DT and ACPI paths are kept separate. The firmware-node framework could be used to unify both paths in a future patch. To support leds-pwm driver, an additional method devm_fwnode_pwm_get() which supports both ACPI and DT configuration is exported. Signed-off-by: Nikolaus Voss --- drivers/pwm/core.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/pwm.h | 9 ++++ 2 files changed, 122 insertions(+) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 275b5f399a1a..5fed419d0833 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -6,6 +6,7 @@ * Copyright (C) 2011-2012 Avionic Design GmbH */ +#include #include #include #include @@ -700,6 +701,76 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id) } EXPORT_SYMBOL_GPL(of_pwm_get); +static struct pwm_chip *device_to_pwmchip(struct device *dev) +{ + struct pwm_chip *chip; + + mutex_lock(&pwm_lock); + + list_for_each_entry(chip, &pwm_chips, list) { + struct acpi_device *adev = ACPI_COMPANION(chip->dev); + + if ((chip->dev == dev) || (adev && &adev->dev == dev)) { + mutex_unlock(&pwm_lock); + return chip; + } + } + + mutex_unlock(&pwm_lock); + + return ERR_PTR(-EPROBE_DEFER); +} + +/** + * acpi_pwm_get() - request a PWM via parsing "pwms" property in ACPI + * @fwnode: firmware node to get the "pwm" property from + * + * Returns the PWM device parsed from the fwnode and index specified in the + * "pwms" property or a negative error-code on failure. + * Values parsed from the device tree are stored in the returned PWM device + * object. + * + * This is analogous to of_pwm_get() except con_id is not yet supported. + * ACPI entries must look like + * Package () {"pwms", Package () + * { , , [, ]}} + * + * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded + * error code on failure. + */ +static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode) +{ + struct fwnode_reference_args args; + struct pwm_chip *chip; + struct pwm_device *pwm = ERR_PTR(-ENODEV); + int ret; + + memset(&args, 0, sizeof(args)); + ret = __acpi_node_get_property_reference(fwnode, "pwms", 0, 3, &args); + + if (!to_acpi_device_node(args.fwnode)) + return ERR_PTR(-EINVAL); + + if (args.nargs < 2) + return ERR_PTR(-EPROTO); + + chip = device_to_pwmchip(&to_acpi_device_node(args.fwnode)->dev); + if (IS_ERR(chip)) + return ERR_CAST(chip); + + pwm = pwm_request_from_chip(chip, args.args[0], NULL); + if (IS_ERR(pwm)) + return pwm; + + pwm->args.period = args.args[1]; + pwm->args.polarity = PWM_POLARITY_NORMAL; + + if (args.nargs > 2 && args.args[2] & PWM_POLARITY_INVERTED) + pwm->args.polarity = PWM_POLARITY_INVERSED; + + return pwm; +} + /** * pwm_add_table() - register PWM device consumers * @table: array of consumers to register @@ -763,6 +834,10 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) return of_pwm_get(dev->of_node, con_id); + /* then lookup via ACPI */ + if (dev && is_acpi_node(dev->fwnode)) + return acpi_pwm_get(dev->fwnode); + /* * We look up the provider in the static table typically provided by * board setup code. We first try to lookup the consumer device by @@ -942,6 +1017,44 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, } EXPORT_SYMBOL_GPL(devm_of_pwm_get); +/** + * devm_fwnode_pwm_get() - request a resource managed PWM from firmware node + * @dev: device for PWM consumer + * @fwnode: firmware node to get the PWM from + * @con_id: consumer name + * + * Returns the PWM device parsed from the firmware node. See of_pwm_get() and + * acpi_pwm_get() for a detailed description. + * + * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded + * error code on failure. + */ +struct pwm_device *devm_fwnode_pwm_get(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id) +{ + struct pwm_device **ptr, *pwm = ERR_PTR(-ENODEV); + + ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + if (is_of_node(fwnode)) + pwm = of_pwm_get(to_of_node(fwnode), con_id); + else if (is_acpi_node(fwnode)) + pwm = acpi_pwm_get(fwnode); + + if (!IS_ERR(pwm)) { + *ptr = pwm; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return pwm; +} +EXPORT_SYMBOL_GPL(devm_fwnode_pwm_get); + static int devm_pwm_match(struct device *dev, void *res, void *data) { struct pwm_device **p = res; diff --git a/include/linux/pwm.h b/include/linux/pwm.h index eaa5c6e3fc9f..1a635916cdfb 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -411,6 +411,9 @@ void pwm_put(struct pwm_device *pwm); struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id); struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, const char *con_id); +struct pwm_device *devm_fwnode_pwm_get(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id); void devm_pwm_put(struct device *dev, struct pwm_device *pwm); #else static inline struct pwm_device *pwm_request(int pwm_id, const char *label) @@ -516,6 +519,12 @@ static inline struct pwm_device *devm_of_pwm_get(struct device *dev, return ERR_PTR(-ENODEV); } +static inline struct pwm_device *devm_fwnode_pwm_get( + struct device *dev, struct fwnode_handle *fwnode, const char *con_id) +{ + return ERR_PTR(-ENODEV); +} + static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm) { } From patchwork Wed Jun 12 08:36:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolaus Voss X-Patchwork-Id: 10988965 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 BA0A01708 for ; Wed, 12 Jun 2019 08:36:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A93A8289B9 for ; Wed, 12 Jun 2019 08:36:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9CA66289BF; Wed, 12 Jun 2019 08:36:43 +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 2D37E289BA for ; Wed, 12 Jun 2019 08:36:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726778AbfFLIgm (ORCPT ); Wed, 12 Jun 2019 04:36:42 -0400 Received: from mail.steuer-voss.de ([85.183.69.95]:43468 "EHLO mail.steuer-voss.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727027AbfFLIgl (ORCPT ); Wed, 12 Jun 2019 04:36:41 -0400 Received: from pc-niv.weinmann.com (localhost [127.0.0.1]) by mail.steuer-voss.de (Postfix) with ESMTP id 22FC54D06D; Wed, 12 Jun 2019 10:36:39 +0200 (CEST) From: Nikolaus Voss To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Erik Schmauss , Jacek Anaszewski , Pavel Machek , Dan Murphy , Thierry Reding Cc: Nikolaus Voss , linux-acpi@vger.kernel.org, devel@acpica.org, linux-leds@vger.kernel.org, linux-pwm@vger.kernel.org, linux-kernel@vger.kernel.org, nv@vosn.de Subject: [PATCH v2 3/3] leds-pwm.c: support ACPI via firmware-node framework Date: Wed, 12 Jun 2019 10:36:08 +0200 Message-Id: <5df196d63671205d6722d21bec0ae5857a6b91eb.1560327219.git.nikolaus.voss@loewensteinmedical.de> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP DT specific handling is replaced by firmware-node abstration to support ACPI specification of PWM LEDS. Example ASL: Device (PWML) { Name (_HID, "PRP0001") Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () {"compatible", Package () {"pwm-leds"}}}}) Device (PWL0) { Name (_HID, "PRP0001") Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () {"label", "alarm-led"}, Package () {"pwms", Package () {\_SB_.PCI0.PWM, 0, 600000, 0}}, Package () {"linux,default-state", "off"}}}) } } Signed-off-by: Nikolaus Voss Acked-by: Pavel Machek --- drivers/leds/leds-pwm.c | 45 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index af08bcdc4fd8..3ce4d53c0cc9 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -75,7 +75,7 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds) } static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, - struct led_pwm *led, struct device_node *child) + struct led_pwm *led, struct fwnode_handle *fwnode) { struct led_pwm_data *led_data = &priv->leds[priv->num_leds]; struct pwm_args pargs; @@ -88,8 +88,8 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, led_data->cdev.max_brightness = led->max_brightness; led_data->cdev.flags = LED_CORE_SUSPENDRESUME; - if (child) - led_data->pwm = devm_of_pwm_get(dev, child, NULL); + if (fwnode) + led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL); else led_data->pwm = devm_pwm_get(dev, led->name); if (IS_ERR(led_data->pwm)) { @@ -114,7 +114,8 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, if (!led_data->period && (led->pwm_period_ns > 0)) led_data->period = led->pwm_period_ns; - ret = devm_of_led_classdev_register(dev, child, &led_data->cdev); + ret = devm_of_led_classdev_register(dev, to_of_node(fwnode), + &led_data->cdev); if (ret == 0) { priv->num_leds++; led_pwm_set(&led_data->cdev, led_data->cdev.brightness); @@ -126,27 +127,35 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, return ret; } -static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv) +static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv) { - struct device_node *child; + struct fwnode_handle *fwnode; struct led_pwm led; int ret = 0; memset(&led, 0, sizeof(led)); - for_each_child_of_node(dev->of_node, child) { - led.name = of_get_property(child, "label", NULL) ? : - child->name; + device_for_each_child_node(dev, fwnode) { + ret = fwnode_property_read_string(fwnode, "label", &led.name); + if (ret && is_of_node(fwnode)) + led.name = to_of_node(fwnode)->name; - led.default_trigger = of_get_property(child, - "linux,default-trigger", NULL); - led.active_low = of_property_read_bool(child, "active-low"); - of_property_read_u32(child, "max-brightness", - &led.max_brightness); + if (!led.name) { + fwnode_handle_put(fwnode); + return -EINVAL; + } - ret = led_pwm_add(dev, priv, &led, child); + fwnode_property_read_string(fwnode, "linux,default-trigger", + &led.default_trigger); + + led.active_low = fwnode_property_read_bool(fwnode, + "active-low"); + fwnode_property_read_u32(fwnode, "max-brightness", + &led.max_brightness); + + ret = led_pwm_add(dev, priv, &led, fwnode); if (ret) { - of_node_put(child); + fwnode_handle_put(fwnode); break; } } @@ -164,7 +173,7 @@ static int led_pwm_probe(struct platform_device *pdev) if (pdata) count = pdata->num_leds; else - count = of_get_child_count(pdev->dev.of_node); + count = device_get_child_node_count(&pdev->dev); if (!count) return -EINVAL; @@ -182,7 +191,7 @@ static int led_pwm_probe(struct platform_device *pdev) break; } } else { - ret = led_pwm_create_of(&pdev->dev, priv); + ret = led_pwm_create_fwnode(&pdev->dev, priv); } if (ret)