From patchwork Sat Apr 25 01:00:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Daniel_Gonz=C3=A1lez_Cabanelas?= X-Patchwork-Id: 212217 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 575BCC2BA1A for ; Sat, 25 Apr 2020 01:00:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2393420776 for ; Sat, 25 Apr 2020 01:00:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="KzgWzskI" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726031AbgDYBAu (ORCPT ); Fri, 24 Apr 2020 21:00:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57304 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725874AbgDYBAu (ORCPT ); Fri, 24 Apr 2020 21:00:50 -0400 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EC998C09B049 for ; Fri, 24 Apr 2020 18:00:49 -0700 (PDT) Received: by mail-wm1-x344.google.com with SMTP id v4so11205395wme.1 for ; Fri, 24 Apr 2020 18:00:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=Zm2y20pux0HBQzidL4UY4mhjjf+ysfTwr1Wf1GSZ1Mg=; b=KzgWzskIOgonNN+pLen6LXM+Ie56hNIq4dkkPk+TRPnRAJRsMnPUDqLMGecM3I5kdt 0hDpuPZnydLz6MjPAp/JJu7KBJ4zuPDSmkA0qzI/K2xZxGN6N+uDPTBueo++1epUEL/N HQC3LykXqzFtVUHvwcg5fdOTGWFbhKuUHklts+/G/hwd3I53dmI32UO4KjYvjZLN0mte 6AeyCzKyQ/h4CIosBvdcLL7OUEazgvazHE7XIAQlGkI9HiZENaJm5BWTWhYAnWSy5Z0X 5a3e8T+sxXGdjjYRJMwSKVIE9r1Yy0UuYq0CldENCdrWOUg5uYS9rM2NSTHeyuJRboQA CeYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=Zm2y20pux0HBQzidL4UY4mhjjf+ysfTwr1Wf1GSZ1Mg=; b=rtRjc7vp93myugtRQuvk9aEJvi7e4335HvoLKig2MKQFtxO1bpam5AJBDyrtij1UVs RTy4YGMqCrWcx44ax9on/ptk6009ffKv0ZvwYaD/ls5mlkl+nZGsCgE1jM1eaEpEUt/Q B/vrjc0yWwvT40JcnAat5MokkoH3UWUvUM8toIY+M+c+DYPk59spxbhuyIFeOG69b6gW +5a6WLpzIyTXIoQ+DydPcI4Kt7KKSx4UX9GHEK1EqxaQ3uqxTzMsS68YxDfvNxrFzWM2 maf1RYNgWn63Ygrzc+8CfKN/QP1GS/1voa3FtH/zHDqCsPHpxNkivluIxAlIW/WT5pXr l7Aw== X-Gm-Message-State: AGi0PuZgvUwgFCzpC0C5b4ddd5t/2Hyymbayb9KRyGvE0SEoC5xA8wcn dl5X0RklPrrPw3sfGRc9cmM2gGYM X-Google-Smtp-Source: APiQypKxmwHf/AYb19VpSxGDG2GaJK+69wcxnCnhgGp1BOEDiy/dDJJaTf7UVEf0klT5kd1+WuDRUw== X-Received: by 2002:a1c:3dd6:: with SMTP id k205mr13205996wma.138.1587776448353; Fri, 24 Apr 2020 18:00:48 -0700 (PDT) Received: from tool.localnet ([213.177.195.242]) by smtp.googlemail.com with ESMTPSA id i19sm11189938wrb.16.2020.04.24.18.00.45 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 24 Apr 2020 18:00:47 -0700 (PDT) From: Daniel =?iso-8859-1?q?Gonz=E1lez?= Cabanelas To: linux-pm@vger.kernel.org Subject: [PATCH 1/2] power:reset: add driver for LinkStation power off Date: Sat, 25 Apr 2020 03:00:43 +0200 Message-ID: <8730960.DhLy2TFWpf@tool> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Some Buffalo LinkStations perform the power off operation, at restart time, depending on the state of an output pin (LED) at the ethernet PHY. The driver is required by the Buffalo LinkStation LS421DE (ARM MVEBU), and other models. Without it, the board remains forever halted if a power off command is executed, unless the PSU is disconnected and connected again. Signed-off-by: Daniel González Cabanelas Reviewed-by: Álvaro Fernández Rojas --- drivers/power/reset/Kconfig | 10 ++ drivers/power/reset/Makefile | 1 + drivers/power/reset/linkstation-poweroff.c | 117 +++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 drivers/power/reset/linkstation-poweroff.c diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 8903803020..de948835f8 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -203,6 +203,16 @@ config POWER_RESET_KEYSTONE help Reboot support for the KEYSTONE SoCs. +config POWER_RESET_LINKSTATION + tristate "Buffalo LinkStation power-off driver" + depends on ARCH_MVEBU || COMPILE_TEST + depends on OF_MDIO && PHYLIB + help + Some Buffalo LinkStations use a LED output at the ethernet PHY + to inform the board that a power off operation must be performed + after restarting. This driver sets the LED to the proper state + for restarting or powering off. + config POWER_RESET_SYSCON bool "Generic SYSCON regmap reset driver" depends on OF diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index da37f8b851..a8c83d2470 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_POWER_RESET_GEMINI_POWEROFF) += gemini-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o +obj-${CONFIG_POWER_RESET_LINKSTATION} += linkstation-poweroff.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o diff --git a/drivers/power/reset/linkstation-poweroff.c b/drivers/power/reset/linkstation-poweroff.c new file mode 100644 index 0000000000..b5a4cc2c2b --- /dev/null +++ b/drivers/power/reset/linkstation-poweroff.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LinkStation power off restart driver + * Copyright (C) 2020 Daniel González Cabanelas + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MII_MARVELL_LED_PAGE 3 +#define MII_PHY_LED_CTRL 16 + +#define LED2_OFF (0x8 << 8) +#define LED2_ON (0x9 << 8) +#define LEDMASK GENMASK(11,8) + +static struct phy_device *phydev; + +static void mvphy_reg_led(u16 data) +{ + int rc; + rc = phy_modify_paged(phydev, MII_MARVELL_LED_PAGE, + MII_PHY_LED_CTRL, LEDMASK, data); + if (rc < 0) + dev_err(&phydev->mdio.dev, + "LED2 write register failed, %d\n", rc); +} + +static int linkstation_reboot_notifier(struct notifier_block *nb, + unsigned long action, void *unused) +{ + if (action == SYS_RESTART) + mvphy_reg_led(LED2_ON); + + return NOTIFY_DONE; +} + +static struct notifier_block linkstation_reboot_nb = { + .notifier_call = linkstation_reboot_notifier, +}; + +static void linkstation_poweroff(void) +{ + unregister_reboot_notifier(&linkstation_reboot_nb); + mvphy_reg_led(LED2_OFF); + + kernel_restart("Power off"); +} + +static int linkstation_poweroff_probe(struct platform_device *pdev) +{ + struct mii_bus *bus; + struct device_node *dn; + + dn = of_parse_phandle(pdev->dev.of_node, "phy-handle,led", 0); + + if (dn) { + phydev = of_phy_find_device(dn); + of_node_put(dn); + } else { + dn = of_find_node_by_name(NULL, "mdio"); + if (!dn) + return -ENODEV; + + bus = of_mdio_find_bus(dn); + of_node_put(dn); + if (!bus) + return -EPROBE_DEFER; + + phydev = phy_find_first(bus); + } + + if (!phydev) + return -ENODEV; + + register_reboot_notifier(&linkstation_reboot_nb); + pm_power_off = linkstation_poweroff; + + dev_info(&pdev->dev, "PHY [%s]\n", phydev_name(phydev)); + + return 0; +} + +static int linkstation_poweroff_remove(struct platform_device *pdev) +{ + pm_power_off = NULL; + unregister_reboot_notifier(&linkstation_reboot_nb); + + return 0; +} + +static const struct of_device_id ls_poweroff_of_match[] = { + { .compatible = "linkstation,power-off", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, ls_poweroff_of_match); + +static struct platform_driver linkstation_poweroff_driver = { + .probe = linkstation_poweroff_probe, + .remove = linkstation_poweroff_remove, + .driver = { + .name = "linkstation_power_off", + .of_match_table = ls_poweroff_of_match, + }, +}; + +module_platform_driver(linkstation_poweroff_driver); + +MODULE_AUTHOR("Daniel González Cabanelas "); +MODULE_DESCRIPTION("LinkStation power off driver"); +MODULE_LICENSE("GPL v2");