diff mbox series

[OpenWrt-Devel,1/2] kernel: add package linkstation-poweroff driver

Message ID 2247807.iZASKD2KPV@tool
State Changes Requested
Delegated to: Petr Štetiar
Headers show
Series [OpenWrt-Devel,1/2] kernel: add package linkstation-poweroff driver | expand

Commit Message

Daniel González Cabanelas April 22, 2020, 9:41 p.m. UTC
Some Buffalo LinkStations perform the power off operation depending on
the state of an output pin (LED) at the ethernet PHY.

This package adds the driver for implementing this function.

The driver is required by the Buffalo LinkStation LS421DE (mvebu target).
Without it, the board reamains forever halted if a power off command is
executed, unless the PSU is disconnected and connected again.

Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
---
 package/kernel/linkstation-pwr/Makefile       |  53 ++++++++
 package/kernel/linkstation-pwr/src/Kconfig    |   9 ++
 package/kernel/linkstation-pwr/src/Makefile   |   1 +
 .../src/linkstation-poweroff.c                | 119 ++++++++++++++++++
 4 files changed, 182 insertions(+)
 create mode 100644 package/kernel/linkstation-pwr/Makefile
 create mode 100644 package/kernel/linkstation-pwr/src/Kconfig
 create mode 100644 package/kernel/linkstation-pwr/src/Makefile
 create mode 100644 package/kernel/linkstation-pwr/src/linkstation-poweroff.c

Comments

Petr Štetiar April 23, 2020, 8:41 a.m. UTC | #1
Daniel González Cabanelas <dgcbueu@gmail.com> [2020-04-22 23:41:56]:

Hi,

> This package adds the driver for implementing this function.

I fail to see how is this driver OpenWrt specific, why the driver should be
maintained by OpenWrt. In other words, please fix this upstream and then just
backport the fixes here, thanks.

-- ynezz
Daniel González Cabanelas April 23, 2020, 9:07 a.m. UTC | #2
El jue., 23 abr. 2020 a las 10:41, Petr Štetiar (<ynezz@true.cz>) escribió:
>
> Daniel González Cabanelas <dgcbueu@gmail.com> [2020-04-22 23:41:56]:
>
> Hi,
>
> > This package adds the driver for implementing this function.
>
> I fail to see how is this driver OpenWrt specific, why the driver should be
> maintained by OpenWrt. In other words, please fix this upstream and then just
> backport the fixes here, thanks.
>
> -- ynezz

Hi Petr, so I should send the patch to Linux ARM Kernel upstream and
then backport this package as a patch into the kernel specific target
patches, right?

Regards
Daniel
Philip Prindeville April 23, 2020, 8:51 p.m. UTC | #3
> On Apr 23, 2020, at 3:07 AM, Daniel González Cabanelas <dgcbueu@gmail.com> wrote:
> 
> El jue., 23 abr. 2020 a las 10:41, Petr Štetiar (<ynezz@true.cz>) escribió:
>> 
>> Daniel González Cabanelas <dgcbueu@gmail.com> [2020-04-22 23:41:56]:
>> 
>> Hi,
>> 
>>> This package adds the driver for implementing this function.
>> 
>> I fail to see how is this driver OpenWrt specific, why the driver should be
>> maintained by OpenWrt. In other words, please fix this upstream and then just
>> backport the fixes here, thanks.
>> 
>> -- ynezz
> 
> Hi Petr, so I should send the patch to Linux ARM Kernel upstream and
> then backport this package as a patch into the kernel specific target
> patches, right?
> 
> Regards
> Daniel


If they accept it, you won’t need to do anything… it will eventually appear in our tree as we adopt the kernel revision having the upstream fixes in it.

-Philip
Petr Štetiar April 24, 2020, 7:33 a.m. UTC | #4
Daniel González Cabanelas <dgcbueu@gmail.com> [2020-04-23 11:07:36]:

Hi,

> Hi Petr, so I should send the patch to Linux ARM Kernel upstream and

running `scripts/get_maintainer.pl your.patch` is going to tell you where to
send this exactly.

> then backport this package as a patch into the kernel specific target
> patches, right?

Yes.

-- ynezz
diff mbox series

Patch

diff --git a/package/kernel/linkstation-pwr/Makefile b/package/kernel/linkstation-pwr/Makefile
new file mode 100644
index 0000000000..f19616c307
--- /dev/null
+++ b/package/kernel/linkstation-pwr/Makefile
@@ -0,0 +1,53 @@ 
+#
+# Copyright (C) 2020 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=linkstation-poweroff
+PKG_RELEASE:=1
+
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/linkstation-poweroff
+  SUBMENU:=Other modules
+  DEPENDS:=@TARGET_mvebu
+  KCONFIG:=
+  TITLE:=Buffalo LinkStation power off driver
+  FILES:=$(PKG_BUILD_DIR)/linkstation-poweroff.ko
+  AUTOLOAD:=$(call AutoLoad,31,linkstation-poweroff,1)
+endef
+
+define KernelPackage/linkstation-poweroff/description
+  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
+  before restarting or powering off.
+endef
+
+EXTRA_KCONFIG:= \
+	CONFIG_POWER_RESET_LINKSTATION=m
+
+EXTRA_CFLAGS:= \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG))))
+
+MAKE_OPTS:= \
+	$(KERNEL_MAKE_FLAGS) \
+	M="$(PKG_BUILD_DIR)" \
+	EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
+	$(EXTRA_KCONFIG)
+
+define Build/Compile
+	$(MAKE) -C "$(LINUX_DIR)" \
+		$(MAKE_OPTS) \
+		modules
+endef
+
+$(eval $(call KernelPackage,linkstation-poweroff))
diff --git a/package/kernel/linkstation-pwr/src/Kconfig b/package/kernel/linkstation-pwr/src/Kconfig
new file mode 100644
index 0000000000..06ed75838c
--- /dev/null
+++ b/package/kernel/linkstation-pwr/src/Kconfig
@@ -0,0 +1,9 @@ 
+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.
diff --git a/package/kernel/linkstation-pwr/src/Makefile b/package/kernel/linkstation-pwr/src/Makefile
new file mode 100644
index 0000000000..36a7093403
--- /dev/null
+++ b/package/kernel/linkstation-pwr/src/Makefile
@@ -0,0 +1 @@ 
+obj-${CONFIG_POWER_RESET_LINKSTATION}	+= linkstation-poweroff.o
diff --git a/package/kernel/linkstation-pwr/src/linkstation-poweroff.c b/package/kernel/linkstation-pwr/src/linkstation-poweroff.c
new file mode 100644
index 0000000000..3a6500209f
--- /dev/null
+++ b/package/kernel/linkstation-pwr/src/linkstation-poweroff.c
@@ -0,0 +1,119 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * LinkStation power off restart driver
+ * Copyright (C) 2020 Daniel González Cabanelas <dgcbueu@gmail.com>
+ *
+ */
+
+#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 {
+		dn = of_find_node_by_name(NULL, "mdio");
+		if (!dn)
+			return -ENODEV;
+
+		bus = of_mdio_find_bus(dn);
+		if (!bus)
+			return -EPROBE_DEFER;
+
+		of_node_put(dn);
+
+		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 <dgcbueu@gmail.com>");
+MODULE_DESCRIPTION("LinkStation power off driver");
+MODULE_LICENSE("GPL v2");