power:reset: add driver for LinkStation power off
PATCH 1/2 power:reset: add driver for LinkStation power off
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.
--- 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
drivers/power/reset/Kconfig +10 -0
@@ -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
drivers/power/reset/Makefile +1 -0
@@ -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
drivers/power/reset/linkstation-poweroff.c new file +117 -0
117 lines not on this page · raw message
Signature · 1 line
2.26.2
[please always add the maintainer to Cc or To, in this case [email protected]]
Hi,
Quoted 11 lines · Daniel González Cabanelas
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 <[email protected]>Reviewed-by Álvaro Fernández Rojas <[email protected]>---
Thanks for the patch. Looks like that hardware was designed by creative hardware engineers trying to impress software engineers with weird designs :)
Quoted 110 lines
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.cdrivers/power/reset/Kconfig +10
-0@@ -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 OFdrivers/power/reset/Makefile +1
-0@@ -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.odrivers/power/reset/linkstation-poweroff.c new file +65
-0@@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* LinkStation power off restart driver +* Copyright (C) 2020 Daniel González Cabanelas <[email protected]> +*/ + +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/of.h> +#include <linux/of_mdio.h> +#include <linux/of_platform.h> +#include <linux/reboot.h> +#include <linux/phy.h> + +#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 {
drivers/power/reset/linkstation-poweroff.c line 75
Quoted 10 lines
drivers/power/reset/linkstation-poweroff.c new file +10
-0+ 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);
do we need this code, or can we just make phy-handle,led mandatory and error out otherwise?
drivers/power/reset/linkstation-poweroff.c line 79
Quoted 4 lines
drivers/power/reset/linkstation-poweroff.c new file +4
-0+ } + +if (!phydev) +return -ENODEV ;
Should this return -EPROBE_DEFER?
drivers/power/reset/linkstation-poweroff.c line 84
Quoted 4 lines
drivers/power/reset/linkstation-poweroff.c new file +4
-0+register_reboot_notifier (&linkstation_reboot_nb); + pm_power_off = linkstation_poweroff; + +dev_info (&pdev->dev,"PHY [%s]\n" ,phydev_name (phydev));
I don't think this deserves more than dev_dbg()
Quoted 22 lines
drivers/power/reset/linkstation-poweroff.c new file +22
-0+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 = {
drivers/power/reset/linkstation-poweroff.c line 117
Quoted 10 lines
drivers/power/reset/linkstation-poweroff.c new file +10
-0+ .name = "linkstation_power_off", + .of_match_table = ls_poweroff_of_match, + }, +}; + +module_platform_driver (linkstation_poweroff_driver); + +MODULE_AUTHOR ("Daniel González Cabanelas <[email protected]>" ); +MODULE_DESCRIPTION ("LinkStation power off driver" ); +MODULE_LICENSE ("GPL v2" );
Otherwise looks good to me,
-- Sebastian
Hi Sebastian. I''ll apply your suggestions.
Thank you
Daniel
Quoted 196 lines · Sebastian Reichel
[please always add the maintainer to Cc or To, in this case [email protected]]
Hi,
Quoted 11 lines · Daniel González Cabanelas
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 <[email protected]>Reviewed-by Álvaro Fernández Rojas <[email protected]>---
Thanks for the patch. Looks like that hardware was designed by creative hardware engineers trying to impress software engineers with weird designs :)
Quoted 110 lines
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.cdrivers/power/reset/Kconfig +10
-0@@ -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 OFdrivers/power/reset/Makefile +1
-0@@ -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.odrivers/power/reset/linkstation-poweroff.c new file +65
-0@@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* LinkStation power off restart driver +* Copyright (C) 2020 Daniel González Cabanelas <[email protected]> +*/ + +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/of.h> +#include <linux/of_mdio.h> +#include <linux/of_platform.h> +#include <linux/reboot.h> +#include <linux/phy.h> + +#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 {drivers/power/reset/linkstation-poweroff.c line 75
Quoted 10 lines
drivers/power/reset/linkstation-poweroff.c new file +10
-0+ 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);do we need this code, or can we just make phy-handle,led mandatory and error out otherwise?
drivers/power/reset/linkstation-poweroff.c line 79
Quoted 4 lines
drivers/power/reset/linkstation-poweroff.c new file +4
-0+ } + +if (!phydev) +return -ENODEV ;Should this return -EPROBE_DEFER?
drivers/power/reset/linkstation-poweroff.c line 84
Quoted 4 lines
drivers/power/reset/linkstation-poweroff.c new file +4
-0+register_reboot_notifier (&linkstation_reboot_nb); + pm_power_off = linkstation_poweroff; + +dev_info (&pdev->dev,"PHY [%s]\n" ,phydev_name (phydev));I don't think this deserves more than
dev_dbg()Quoted 22 lines
drivers/power/reset/linkstation-poweroff.c new file +22
-0+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 = {drivers/power/reset/linkstation-poweroff.c line 117
Quoted 10 lines
drivers/power/reset/linkstation-poweroff.c new file +10
-0+ .name = "linkstation_power_off", + .of_match_table = ls_poweroff_of_match, + }, +}; + +module_platform_driver (linkstation_poweroff_driver); + +MODULE_AUTHOR ("Daniel González Cabanelas <[email protected]>" ); +MODULE_DESCRIPTION ("LinkStation power off driver" ); +MODULE_LICENSE ("GPL v2" );Otherwise looks good to me,
-- Sebastian