From patchwork Fri Jul 1 20:19:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 9210459 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id AA619607D6 for ; Fri, 1 Jul 2016 20:22:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9B2E927FA8 for ; Fri, 1 Jul 2016 20:22:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8FF4F284FC; Fri, 1 Jul 2016 20:22:52 +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=-6.9 required=2.0 tests=BAYES_00,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 0CA1A27FA8 for ; Fri, 1 Jul 2016 20:22:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932145AbcGAUWi (ORCPT ); Fri, 1 Jul 2016 16:22:38 -0400 Received: from mail-wm0-f67.google.com ([74.125.82.67]:36709 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752082AbcGAUUH (ORCPT ); Fri, 1 Jul 2016 16:20:07 -0400 Received: by mail-wm0-f67.google.com with SMTP id c82so7584938wme.3; Fri, 01 Jul 2016 13:19:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=IIuLxYBZ0pnOqlV52SL/A6tdfjm8NRscbTzcKwQwMsE=; b=OQLc3AxymBam3N8QnhZlXRy9ewUE4tvI+wSMksnJweTVrW9f0YdHESXuVEIrGYZxH4 AAx7UX5rpyxNNSxPCWqIBk9Amm4j95QgPABu0I9hMWBAIbYjM1Srp0leubycDPArfEfj LJ7Ij8DpfppLqnC7CfZSVlWvpw7XA9FKG1vkyO5m/+JVCpZeogZcwM4+WoB2fcF++aY6 twSoPxYTBpFaD+NPaFV3d352tTzdX4QNeF2HWFPVtDBzG1gIRH1uOBFNpYOGAbCq/hbq HrS0k0V1jc3keVEOvqt3v9abFFZ+rAqxQqS8L6Hyd8BhBxc/4TlDGRXGyEHTesrTr/3Y G9FA== X-Gm-Message-State: ALyK8tKcX5svWfVIdnNhcyX/8Au1sE6pmlQcjTRFmYxl4ucrAIlrSvrDacXwl2PMSqniQA== X-Received: by 10.194.239.232 with SMTP id vv8mr66257wjc.166.1467404382223; Fri, 01 Jul 2016 13:19:42 -0700 (PDT) Received: from localhost.localdomain ([109.98.36.115]) by smtp.gmail.com with ESMTPSA id zb9sm3890411wjc.34.2016.07.01.13.19.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 01 Jul 2016 13:19:41 -0700 (PDT) From: Octavian Purdila To: "Rafael J . Wysocki" , Len Brown , Matt Fleming , Mark Brown , Wolfram Sang Cc: Joel Becker , linux-acpi@vger.kernel.org, linux-efi@vger.kernel.org, linux-i2c@vger.kernel.org, linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, irina.tirdea@intel.com, leonard.crestez@intel.com, Octavian Purdila Subject: [PATCH v5 5/8] spi: add support for ACPI reconfigure notifications Date: Fri, 1 Jul 2016 23:19:09 +0300 Message-Id: <1467404352-27101-6-git-send-email-octavian.purdila@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1467404352-27101-1-git-send-email-octavian.purdila@intel.com> References: <1467404352-27101-1-git-send-email-octavian.purdila@intel.com> Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds supports for SPI device enumeration and removal via ACPI reconfiguration notifications that are send as a result of an ACPI table load or unload operation. The code is very similar with the device tree reconfiguration code with only small differences in the way we test and set the enumerated state of the device: * the equivalent of device tree's OF_POPULATED flag is the flags.visited field in the ACPI device and the following wrappers are used to manipulate it: acpi_device_enumerated(), acpi_device_set_enumerated() and acpi_device_clear_enumerated() * the device tree code checks of status of the OF_POPULATED flag to avoid trying to create duplicate Linux devices in two places: once when the controller is probed, and once when the reconfigure event is received; in the ACPI code the check is performed only once when the ACPI namespace is searched because this code path is invoked in both of the two mentioned cases The rest of the enumeration handling is similar with device tree: when the Linux device is unregistered the ACPI device is marked as not enumerated; also, when a device remove notification is received we check that the device is in the enumerated state before continuing with the removal of the Linux device. Signed-off-by: Octavian Purdila Reviewed-by: Mika Westerberg Acked-by: Mark Brown --- drivers/spi/spi.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 77e6e45..7589c8a 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -622,6 +622,8 @@ void spi_unregister_device(struct spi_device *spi) if (spi->dev.of_node) of_node_clear_flag(spi->dev.of_node, OF_POPULATED); + if (ACPI_COMPANION(&spi->dev)) + acpi_device_clear_enumerated(ACPI_COMPANION(&spi->dev)); device_unregister(&spi->dev); } EXPORT_SYMBOL_GPL(spi_unregister_device); @@ -1646,18 +1648,15 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) return 1; } -static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, - void *data, void **return_value) +static acpi_status acpi_register_spi_device(struct spi_master *master, + struct acpi_device *adev) { - struct spi_master *master = data; struct list_head resource_list; - struct acpi_device *adev; struct spi_device *spi; int ret; - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - if (acpi_bus_get_status(adev) || !adev->status.present) + if (acpi_bus_get_status(adev) || !adev->status.present || + acpi_device_enumerated(adev)) return AE_OK; spi = spi_alloc_device(master); @@ -1683,6 +1682,8 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, if (spi->irq < 0) spi->irq = acpi_dev_gpio_irq_get(adev, 0); + acpi_device_set_enumerated(adev); + adev->power.flags.ignore_parent = true; strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias)); if (spi_add_device(spi)) { @@ -1695,6 +1696,18 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, return AE_OK; } +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct spi_master *master = data; + struct acpi_device *adev; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + return acpi_register_spi_device(master, adev); +} + static void acpi_register_spi_devices(struct spi_master *master) { acpi_status status; @@ -3107,6 +3120,77 @@ static struct notifier_block spi_of_notifier = { extern struct notifier_block spi_of_notifier; #endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ +#if IS_ENABLED(CONFIG_ACPI) +static int spi_acpi_master_match(struct device *dev, const void *data) +{ + return ACPI_COMPANION(dev->parent) == data; +} + +static int spi_acpi_device_match(struct device *dev, void *data) +{ + return ACPI_COMPANION(dev) == data; +} + +static struct spi_master *acpi_spi_find_master_by_adev(struct acpi_device *adev) +{ + struct device *dev; + + dev = class_find_device(&spi_master_class, NULL, adev, + spi_acpi_master_match); + if (!dev) + return NULL; + + return container_of(dev, struct spi_master, dev); +} + +static struct spi_device *acpi_spi_find_device_by_adev(struct acpi_device *adev) +{ + struct device *dev; + + dev = bus_find_device(&spi_bus_type, NULL, adev, spi_acpi_device_match); + + return dev ? to_spi_device(dev) : NULL; +} + +static int acpi_spi_notify(struct notifier_block *nb, unsigned long value, + void *arg) +{ + struct acpi_device *adev = arg; + struct spi_master *master; + struct spi_device *spi; + + switch (value) { + case ACPI_RECONFIG_DEVICE_ADD: + master = acpi_spi_find_master_by_adev(adev->parent); + if (!master) + break; + + acpi_register_spi_device(master, adev); + put_device(&master->dev); + break; + case ACPI_RECONFIG_DEVICE_REMOVE: + if (!acpi_device_enumerated(adev)) + break; + + spi = acpi_spi_find_device_by_adev(adev); + if (!spi) + break; + + spi_unregister_device(spi); + put_device(&spi->dev); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block spi_acpi_notifier = { + .notifier_call = acpi_spi_notify, +}; +#else +extern struct notifier_block spi_acpi_notifier; +#endif + static int __init spi_init(void) { int status; @@ -3127,6 +3211,8 @@ static int __init spi_init(void) if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_register(&spi_of_notifier)); + if (IS_ENABLED(CONFIG_ACPI)) + WARN_ON(acpi_reconfig_notifier_register(&spi_acpi_notifier)); return 0;