From: Roger Shimizu <rogershimizu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Roger Shimizu
<rogershimizu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>,
Martin Michlmayr <tbm-R+vWnYXSFMfQT0dZR+AlfA@public.gmane.org>,
Sylver Bruneau
<sylver.bruneau-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>,
Herbert Valerio Riedel <hvr-mXXj517/zsQ@public.gmane.org>,
Ryan Tandy <ryan-pRYBVO4bdZ33fQ9qLvQP4Q@public.gmane.org>,
Florian Fainelli
<f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
Subject: [PATCH v4 1/2] power: reset: add linkstation-reset driver
Date: Sun, 8 Jan 2017 00:04:50 +0900 [thread overview]
Message-ID: <20170107150451.17912-2-rogershimizu@gmail.com> (raw)
In-Reply-To: <20170107150451.17912-1-rogershimizu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Buffalo Linkstation / KuroBox and their variants need magic command
sending to UART1 to power-off.
Power driver linkstation-reset implements the magic command and I/O
routine, which come from files listed below:
- arch/arm/mach-orion5x/kurobox_pro-setup.c
- arch/arm/mach-orion5x/terastation_pro2-setup.c
To: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
Cc: Martin Michlmayr <tbm-R+vWnYXSFMfQT0dZR+AlfA@public.gmane.org>
Cc: Sylver Bruneau <sylver.bruneau-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Cc: Herbert Valerio Riedel <hvr-mXXj517/zsQ@public.gmane.org>
Cc: Ryan Tandy <ryan-pRYBVO4bdZ33fQ9qLvQP4Q@public.gmane.org>
Cc: Florian Fainelli <f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
Reported-by: Ryan Tandy <ryan-pRYBVO4bdZ33fQ9qLvQP4Q@public.gmane.org>
Tested-by: Ryan Tandy <ryan-pRYBVO4bdZ33fQ9qLvQP4Q@public.gmane.org>
Signed-off-by: Roger Shimizu <rogershimizu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/power/reset/Kconfig | 10 ++
drivers/power/reset/Makefile | 1 +
drivers/power/reset/linkstation-reset.c | 270 ++++++++++++++++++++++++++++++++
3 files changed, 281 insertions(+)
create mode 100644 drivers/power/reset/linkstation-reset.c
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index c74c3f67b8da..77c44cad7ece 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -98,6 +98,16 @@ config POWER_RESET_IMX
say N here or disable in dts to make sure pm_power_off never be
overwrote wrongly by this driver.
+config POWER_RESET_LINKSTATION
+ bool "Buffalo Linkstation and its variants reset driver"
+ depends on OF_GPIO && PLAT_ORION
+ help
+ This driver supports power off Buffalo Linkstation / KuroBox Pro
+ NAS and their variants by sending commands to the micro-controller
+ which controls the main power.
+
+ Say Y if you have a Buffalo Linkstation / KuroBox Pro NAS.
+
config POWER_RESET_MSM
bool "Qualcomm MSM power-off driver"
depends on ARCH_QCOM
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 1be307c7fc25..692ba6417cfb 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -9,6 +9,7 @@ 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_IMX) += imx-snvs-poweroff.o
+obj-$(CONFIG_POWER_RESET_LINKSTATION) += linkstation-reset.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
diff --git a/drivers/power/reset/linkstation-reset.c b/drivers/power/reset/linkstation-reset.c
new file mode 100644
index 000000000000..c191b7671076
--- /dev/null
+++ b/drivers/power/reset/linkstation-reset.c
@@ -0,0 +1,270 @@
+/*
+ * Buffalo Linkstation power reset driver.
+ * It may also be used on following devices:
+ * - KuroBox Pro
+ * - Buffalo Linkstation Pro (LS-GL)
+ * - Buffalo Terastation Pro II/Live
+ * - Buffalo Linkstation Duo (LS-WTGL)
+ * - Buffalo Linkstation Mini (LS-WSGL)
+ *
+ * Copyright (C) 2016 Roger Shimizu <rogershimizu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ * Based on the code from:
+ *
+ * Copyright (C) 2012 Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
+ * Copyright (C) 2009 Martin Michlmayr <tbm-R+vWnYXSFMfQT0dZR+AlfA@public.gmane.org>
+ * Copyright (C) 2008 Byron Bradley <byron.bbradley-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * Copyright (C) 2008 Sylver Bruneau <sylver.bruneau-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
+ * Copyright (C) 2007 Herbert Valerio Riedel <hvr-mXXj517/zsQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serial_reg.h>
+#include <linux/kallsyms.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#define UART1_REG(x) ((UART_##x) << 2)
+#define MICON_CMD_SIZE 4
+
+/* 4-byte magic hello command to UART1-attached microcontroller */
+static const unsigned char linkstation_micon_magic[] = {
+ 0x1b,
+ 0x00,
+ 0x07,
+ 0x00
+};
+
+/* for each row, first byte is the size of command */
+static const unsigned char linkstation_power_off_cmd[][MICON_CMD_SIZE] = {
+ { 3, 0x01, 0x35, 0x00},
+ { 2, 0x00, 0x0c},
+ { 2, 0x00, 0x06},
+ {}
+};
+
+struct reset_cfg {
+ u32 baud;
+ const unsigned char *magic;
+ const unsigned char (*cmd)[MICON_CMD_SIZE];
+};
+
+struct device_cfg {
+ const struct device *dev;
+ void __iomem *base;
+ unsigned long tclk;
+ const struct reset_cfg *cfg;
+};
+
+static const struct reset_cfg linkstation_power_off_cfg = {
+ .baud = 38400,
+ .magic = linkstation_micon_magic,
+ .cmd = linkstation_power_off_cmd,
+};
+
+static const struct of_device_id linkstation_reset_of_match_table[] = {
+ { .compatible = "linkstation,power-off",
+ .data = &linkstation_power_off_cfg,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, linkstation_reset_of_match_table);
+
+static int uart1_micon_read(const struct device_cfg *dev, unsigned char *buf, int count)
+{
+ int i;
+ int timeout;
+
+ for (i = 0; i < count; i++) {
+ timeout = 10;
+
+ while (!(readl(dev->base + UART1_REG(LSR)) & UART_LSR_DR)) {
+ if (--timeout == 0)
+ break;
+ udelay(1000);
+ }
+
+ if (timeout == 0)
+ break;
+ buf[i] = readl(dev->base + UART1_REG(RX));
+ }
+
+ /* return read bytes */
+ return i;
+}
+
+static int uart1_micon_write(const struct device_cfg *dev, const unsigned char *buf, int count)
+{
+ int i = 0;
+
+ while (count--) {
+ while (!(readl(dev->base + UART1_REG(LSR)) & UART_LSR_THRE))
+ barrier();
+ writel(buf[i++], dev->base + UART1_REG(TX));
+ }
+
+ return 0;
+}
+
+int uart1_micon_send(const struct device_cfg *dev, const unsigned char *data, int count)
+{
+ int i;
+ unsigned char checksum = 0;
+ unsigned char recv_buf[40];
+ unsigned char send_buf[40];
+ unsigned char correct_ack[3];
+ int retry = 2;
+
+ /* Generate checksum */
+ for (i = 0; i < count; i++)
+ checksum -= data[i];
+
+ do {
+ /* Send data */
+ uart1_micon_write(dev, data, count);
+
+ /* send checksum */
+ uart1_micon_write(dev, &checksum, 1);
+
+ if (uart1_micon_read(dev, recv_buf, sizeof(recv_buf)) <= 3) {
+ dev_err(dev->dev, ">%s: receive failed.\n", __func__);
+
+ /* send preamble to clear the receive buffer */
+ memset(&send_buf, 0xff, sizeof(send_buf));
+ uart1_micon_write(dev, send_buf, sizeof(send_buf));
+
+ /* make dummy reads */
+ mdelay(100);
+ uart1_micon_read(dev, recv_buf, sizeof(recv_buf));
+ } else {
+ /* Generate expected ack */
+ correct_ack[0] = 0x01;
+ correct_ack[1] = data[1];
+ correct_ack[2] = 0x00;
+
+ /* checksum Check */
+ if ((recv_buf[0] + recv_buf[1] + recv_buf[2] +
+ recv_buf[3]) & 0xFF) {
+ dev_err(dev->dev, ">%s: Checksum Error : "
+ "Received data[%02x, %02x, %02x, %02x]"
+ "\n", __func__, recv_buf[0],
+ recv_buf[1], recv_buf[2], recv_buf[3]);
+ } else {
+ /* Check Received Data */
+ if (correct_ack[0] == recv_buf[0] &&
+ correct_ack[1] == recv_buf[1] &&
+ correct_ack[2] == recv_buf[2]) {
+ /* Interval for next command */
+ mdelay(10);
+
+ /* Receive ACK */
+ return 0;
+ }
+ }
+ /* Received NAK or illegal Data */
+ dev_err(dev->dev, ">%s: Error : NAK or Illegal Data "
+ "Received\n", __func__);
+ }
+ } while (retry--);
+
+ /* Interval for next command */
+ mdelay(10);
+
+ return -1;
+}
+
+static struct device_cfg reset;
+
+static void linkstation_reset(void)
+{
+ const unsigned divisor = ((reset.tclk + (8 * reset.cfg->baud)) / (16 * reset.cfg->baud));
+ int i;
+
+ pr_err("%s: triggering power-off...\n", __func__);
+
+ /* hijack UART1 and reset into sane state */
+ writel(0x83, reset.base + UART1_REG(LCR));
+ writel(divisor & 0xff, reset.base + UART1_REG(DLL));
+ writel((divisor >> 8) & 0xff, reset.base + UART1_REG(DLM));
+ writel(reset.cfg->magic[0], reset.base + UART1_REG(LCR));
+ writel(reset.cfg->magic[1], reset.base + UART1_REG(IER));
+ writel(reset.cfg->magic[2], reset.base + UART1_REG(FCR));
+ writel(reset.cfg->magic[3], reset.base + UART1_REG(MCR));
+
+ /* send the power-off command to PIC */
+ for(i = 0; reset.cfg->cmd[i][0] > 0; i ++) {
+ /* [0] is size of the command; command starts from [1] */
+ uart1_micon_send(&reset, &(reset.cfg->cmd[i][1]), reset.cfg->cmd[i][0]);
+ }
+}
+
+static int linkstation_reset_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ struct clk *clk;
+
+ const struct of_device_id *match =
+ of_match_node(linkstation_reset_of_match_table, np);
+ reset.cfg = match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Missing resource");
+ return -EINVAL;
+ }
+
+ reset.dev = &pdev->dev;
+ reset.base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!reset.base) {
+ dev_err(reset.dev, "Unable to map resource");
+ return -EINVAL;
+ }
+
+ /* We need to know tclk in order to calculate the UART divisor */
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(reset.dev, "Clk missing");
+ return PTR_ERR(clk);
+ }
+
+ reset.tclk = clk_get_rate(clk);
+
+ /* Check that nothing else has already setup a handler */
+ if (!pm_power_off) {
+ pm_power_off = linkstation_reset;
+ }
+
+ return 0;
+}
+
+static int linkstation_reset_remove(struct platform_device *pdev)
+{
+ if (pm_power_off == linkstation_reset)
+ pm_power_off = NULL;
+ return 0;
+}
+
+static struct platform_driver linkstation_reset_driver = {
+ .probe = linkstation_reset_probe,
+ .remove = linkstation_reset_remove,
+ .driver = {
+ .name = "linkstation_reset",
+ .of_match_table = of_match_ptr(linkstation_reset_of_match_table),
+ },
+};
+
+module_platform_driver(linkstation_reset_driver);
+
+MODULE_AUTHOR("Roger Shimizu <rogershimizu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
+MODULE_DESCRIPTION("Linkstation Reset driver");
+MODULE_LICENSE("GPL v2");
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
WARNING: multiple messages have this Message-ID (diff)
From: rogershimizu@gmail.com (Roger Shimizu)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 1/2] power: reset: add linkstation-reset driver
Date: Sun, 8 Jan 2017 00:04:50 +0900 [thread overview]
Message-ID: <20170107150451.17912-2-rogershimizu@gmail.com> (raw)
In-Reply-To: <20170107150451.17912-1-rogershimizu@gmail.com>
Buffalo Linkstation / KuroBox and their variants need magic command
sending to UART1 to power-off.
Power driver linkstation-reset implements the magic command and I/O
routine, which come from files listed below:
- arch/arm/mach-orion5x/kurobox_pro-setup.c
- arch/arm/mach-orion5x/terastation_pro2-setup.c
To: Sebastian Reichel <sre@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Martin Michlmayr <tbm@cyrius.com>
Cc: Sylver Bruneau <sylver.bruneau@googlemail.com>
Cc: Herbert Valerio Riedel <hvr@gnu.org>
Cc: Ryan Tandy <ryan@nardis.ca>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: linux-pm at vger.kernel.org
Cc: devicetree at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Reported-by: Ryan Tandy <ryan@nardis.ca>
Tested-by: Ryan Tandy <ryan@nardis.ca>
Signed-off-by: Roger Shimizu <rogershimizu@gmail.com>
---
drivers/power/reset/Kconfig | 10 ++
drivers/power/reset/Makefile | 1 +
drivers/power/reset/linkstation-reset.c | 270 ++++++++++++++++++++++++++++++++
3 files changed, 281 insertions(+)
create mode 100644 drivers/power/reset/linkstation-reset.c
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index c74c3f67b8da..77c44cad7ece 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -98,6 +98,16 @@ config POWER_RESET_IMX
say N here or disable in dts to make sure pm_power_off never be
overwrote wrongly by this driver.
+config POWER_RESET_LINKSTATION
+ bool "Buffalo Linkstation and its variants reset driver"
+ depends on OF_GPIO && PLAT_ORION
+ help
+ This driver supports power off Buffalo Linkstation / KuroBox Pro
+ NAS and their variants by sending commands to the micro-controller
+ which controls the main power.
+
+ Say Y if you have a Buffalo Linkstation / KuroBox Pro NAS.
+
config POWER_RESET_MSM
bool "Qualcomm MSM power-off driver"
depends on ARCH_QCOM
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 1be307c7fc25..692ba6417cfb 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -9,6 +9,7 @@ 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_IMX) += imx-snvs-poweroff.o
+obj-$(CONFIG_POWER_RESET_LINKSTATION) += linkstation-reset.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
diff --git a/drivers/power/reset/linkstation-reset.c b/drivers/power/reset/linkstation-reset.c
new file mode 100644
index 000000000000..c191b7671076
--- /dev/null
+++ b/drivers/power/reset/linkstation-reset.c
@@ -0,0 +1,270 @@
+/*
+ * Buffalo Linkstation power reset driver.
+ * It may also be used on following devices:
+ * - KuroBox Pro
+ * - Buffalo Linkstation Pro (LS-GL)
+ * - Buffalo Terastation Pro II/Live
+ * - Buffalo Linkstation Duo (LS-WTGL)
+ * - Buffalo Linkstation Mini (LS-WSGL)
+ *
+ * Copyright (C) 2016 Roger Shimizu <rogershimizu@gmail.com>
+ *
+ * Based on the code from:
+ *
+ * Copyright (C) 2012 Andrew Lunn <andrew@lunn.ch>
+ * Copyright (C) 2009 Martin Michlmayr <tbm@cyrius.com>
+ * Copyright (C) 2008 Byron Bradley <byron.bbradley@gmail.com>
+ * Copyright (C) 2008 Sylver Bruneau <sylver.bruneau@googlemail.com>
+ * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serial_reg.h>
+#include <linux/kallsyms.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#define UART1_REG(x) ((UART_##x) << 2)
+#define MICON_CMD_SIZE 4
+
+/* 4-byte magic hello command to UART1-attached microcontroller */
+static const unsigned char linkstation_micon_magic[] = {
+ 0x1b,
+ 0x00,
+ 0x07,
+ 0x00
+};
+
+/* for each row, first byte is the size of command */
+static const unsigned char linkstation_power_off_cmd[][MICON_CMD_SIZE] = {
+ { 3, 0x01, 0x35, 0x00},
+ { 2, 0x00, 0x0c},
+ { 2, 0x00, 0x06},
+ {}
+};
+
+struct reset_cfg {
+ u32 baud;
+ const unsigned char *magic;
+ const unsigned char (*cmd)[MICON_CMD_SIZE];
+};
+
+struct device_cfg {
+ const struct device *dev;
+ void __iomem *base;
+ unsigned long tclk;
+ const struct reset_cfg *cfg;
+};
+
+static const struct reset_cfg linkstation_power_off_cfg = {
+ .baud = 38400,
+ .magic = linkstation_micon_magic,
+ .cmd = linkstation_power_off_cmd,
+};
+
+static const struct of_device_id linkstation_reset_of_match_table[] = {
+ { .compatible = "linkstation,power-off",
+ .data = &linkstation_power_off_cfg,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, linkstation_reset_of_match_table);
+
+static int uart1_micon_read(const struct device_cfg *dev, unsigned char *buf, int count)
+{
+ int i;
+ int timeout;
+
+ for (i = 0; i < count; i++) {
+ timeout = 10;
+
+ while (!(readl(dev->base + UART1_REG(LSR)) & UART_LSR_DR)) {
+ if (--timeout == 0)
+ break;
+ udelay(1000);
+ }
+
+ if (timeout == 0)
+ break;
+ buf[i] = readl(dev->base + UART1_REG(RX));
+ }
+
+ /* return read bytes */
+ return i;
+}
+
+static int uart1_micon_write(const struct device_cfg *dev, const unsigned char *buf, int count)
+{
+ int i = 0;
+
+ while (count--) {
+ while (!(readl(dev->base + UART1_REG(LSR)) & UART_LSR_THRE))
+ barrier();
+ writel(buf[i++], dev->base + UART1_REG(TX));
+ }
+
+ return 0;
+}
+
+int uart1_micon_send(const struct device_cfg *dev, const unsigned char *data, int count)
+{
+ int i;
+ unsigned char checksum = 0;
+ unsigned char recv_buf[40];
+ unsigned char send_buf[40];
+ unsigned char correct_ack[3];
+ int retry = 2;
+
+ /* Generate checksum */
+ for (i = 0; i < count; i++)
+ checksum -= data[i];
+
+ do {
+ /* Send data */
+ uart1_micon_write(dev, data, count);
+
+ /* send checksum */
+ uart1_micon_write(dev, &checksum, 1);
+
+ if (uart1_micon_read(dev, recv_buf, sizeof(recv_buf)) <= 3) {
+ dev_err(dev->dev, ">%s: receive failed.\n", __func__);
+
+ /* send preamble to clear the receive buffer */
+ memset(&send_buf, 0xff, sizeof(send_buf));
+ uart1_micon_write(dev, send_buf, sizeof(send_buf));
+
+ /* make dummy reads */
+ mdelay(100);
+ uart1_micon_read(dev, recv_buf, sizeof(recv_buf));
+ } else {
+ /* Generate expected ack */
+ correct_ack[0] = 0x01;
+ correct_ack[1] = data[1];
+ correct_ack[2] = 0x00;
+
+ /* checksum Check */
+ if ((recv_buf[0] + recv_buf[1] + recv_buf[2] +
+ recv_buf[3]) & 0xFF) {
+ dev_err(dev->dev, ">%s: Checksum Error : "
+ "Received data[%02x, %02x, %02x, %02x]"
+ "\n", __func__, recv_buf[0],
+ recv_buf[1], recv_buf[2], recv_buf[3]);
+ } else {
+ /* Check Received Data */
+ if (correct_ack[0] == recv_buf[0] &&
+ correct_ack[1] == recv_buf[1] &&
+ correct_ack[2] == recv_buf[2]) {
+ /* Interval for next command */
+ mdelay(10);
+
+ /* Receive ACK */
+ return 0;
+ }
+ }
+ /* Received NAK or illegal Data */
+ dev_err(dev->dev, ">%s: Error : NAK or Illegal Data "
+ "Received\n", __func__);
+ }
+ } while (retry--);
+
+ /* Interval for next command */
+ mdelay(10);
+
+ return -1;
+}
+
+static struct device_cfg reset;
+
+static void linkstation_reset(void)
+{
+ const unsigned divisor = ((reset.tclk + (8 * reset.cfg->baud)) / (16 * reset.cfg->baud));
+ int i;
+
+ pr_err("%s: triggering power-off...\n", __func__);
+
+ /* hijack UART1 and reset into sane state */
+ writel(0x83, reset.base + UART1_REG(LCR));
+ writel(divisor & 0xff, reset.base + UART1_REG(DLL));
+ writel((divisor >> 8) & 0xff, reset.base + UART1_REG(DLM));
+ writel(reset.cfg->magic[0], reset.base + UART1_REG(LCR));
+ writel(reset.cfg->magic[1], reset.base + UART1_REG(IER));
+ writel(reset.cfg->magic[2], reset.base + UART1_REG(FCR));
+ writel(reset.cfg->magic[3], reset.base + UART1_REG(MCR));
+
+ /* send the power-off command to PIC */
+ for(i = 0; reset.cfg->cmd[i][0] > 0; i ++) {
+ /* [0] is size of the command; command starts from [1] */
+ uart1_micon_send(&reset, &(reset.cfg->cmd[i][1]), reset.cfg->cmd[i][0]);
+ }
+}
+
+static int linkstation_reset_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ struct clk *clk;
+
+ const struct of_device_id *match =
+ of_match_node(linkstation_reset_of_match_table, np);
+ reset.cfg = match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Missing resource");
+ return -EINVAL;
+ }
+
+ reset.dev = &pdev->dev;
+ reset.base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!reset.base) {
+ dev_err(reset.dev, "Unable to map resource");
+ return -EINVAL;
+ }
+
+ /* We need to know tclk in order to calculate the UART divisor */
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(reset.dev, "Clk missing");
+ return PTR_ERR(clk);
+ }
+
+ reset.tclk = clk_get_rate(clk);
+
+ /* Check that nothing else has already setup a handler */
+ if (!pm_power_off) {
+ pm_power_off = linkstation_reset;
+ }
+
+ return 0;
+}
+
+static int linkstation_reset_remove(struct platform_device *pdev)
+{
+ if (pm_power_off == linkstation_reset)
+ pm_power_off = NULL;
+ return 0;
+}
+
+static struct platform_driver linkstation_reset_driver = {
+ .probe = linkstation_reset_probe,
+ .remove = linkstation_reset_remove,
+ .driver = {
+ .name = "linkstation_reset",
+ .of_match_table = of_match_ptr(linkstation_reset_of_match_table),
+ },
+};
+
+module_platform_driver(linkstation_reset_driver);
+
+MODULE_AUTHOR("Roger Shimizu <rogershimizu@gmail.com>");
+MODULE_DESCRIPTION("Linkstation Reset driver");
+MODULE_LICENSE("GPL v2");
--
2.11.0
next prev parent reply other threads:[~2017-01-07 15:04 UTC|newest]
Thread overview: 68+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-12-05 12:45 [PATCH 0/3] make kurobox-pro be able to shutdown after device-tree migration Roger Shimizu
2016-12-05 12:45 ` [PATCH 1/3] power: reset: make qnap-poweroff flexible on hello magic command to uart1 Roger Shimizu
2016-12-05 12:45 ` [PATCH 2/3] power: reset: make qnap-poweroff flexible on length of power-off command Roger Shimizu
2016-12-05 12:45 ` [PATCH 3/3] power: reset: make qnap-poweroff support kurobox-pro Roger Shimizu
2016-12-06 17:34 ` [PATCH 0/3] make kurobox-pro be able to shutdown after device-tree migration Andrew Lunn
2016-12-07 17:24 ` [PATCH v1 " Roger Shimizu
2016-12-07 17:24 ` [PATCH v1 1/3] power: reset: make qnap-poweroff flexible on hello magic command to uart1 Roger Shimizu
2016-12-07 17:24 ` [PATCH v1 2/3] power: reset: make qnap-poweroff flexible on length of power-off command Roger Shimizu
2016-12-07 17:24 ` [PATCH v1 3/3] power: reset: make qnap-poweroff support kurobox-pro Roger Shimizu
2016-12-07 18:04 ` [PATCH v1 0/3] make kurobox-pro be able to shutdown after device-tree migration Andrew Lunn
2016-12-16 10:05 ` [PATCH v2] power: reset: add linkstation-reset driver Roger Shimizu
2016-12-19 0:34 ` Roger Shimizu
2016-12-19 15:38 ` Sebastian Reichel
2016-12-19 16:03 ` Andrew Lunn
2016-12-19 16:12 ` Roger Shimizu
2016-12-19 17:37 ` Roger Shimizu
[not found] ` <CAEQ9gEnQEHdcA4ox3teOXKcrdf2AAqUMp=A6W6c7nXhk4VrKiw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-12-21 15:59 ` Sebastian Reichel
2016-12-21 16:41 ` Andrew Lunn
[not found] ` <20161221164136.GM30952-g2DYL2Zd6BY@public.gmane.org>
2016-12-22 14:49 ` Sebastian Reichel
2016-12-26 16:13 ` Roger Shimizu
2016-12-27 7:06 ` [PATCH v3 0/3] make kurobox-pro be able to shutdown after device-tree migration Roger Shimizu
2016-12-27 7:06 ` Roger Shimizu
2016-12-27 7:06 ` [PATCH v3 1/3] power: reset: add linkstation-reset driver Roger Shimizu
2016-12-27 7:06 ` Roger Shimizu
[not found] ` <20161227070611.14852-2-rogershimizu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-01-03 5:19 ` Florian Fainelli
2017-01-03 5:19 ` Florian Fainelli
2017-01-03 13:09 ` Andrew Lunn
2017-01-03 13:09 ` Andrew Lunn
2017-01-03 14:08 ` Roger Shimizu
2017-01-03 14:08 ` Roger Shimizu
[not found] ` <CAEQ9gE=MoQcr3eX0DAxZtvx0FW9pzgkUGjdxKHcsKwH7_+UsUw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-01-03 18:39 ` Florian Fainelli
2017-01-03 18:39 ` Florian Fainelli
2016-12-27 7:06 ` [PATCH v3 2/3] DT: bingdings: power: reset: add linkstation-reset doc Roger Shimizu
2016-12-27 7:06 ` Roger Shimizu
2017-01-03 5:21 ` Florian Fainelli
2017-01-03 5:21 ` Florian Fainelli
2017-01-03 13:12 ` Andrew Lunn
2017-01-03 13:12 ` Andrew Lunn
2017-01-03 14:11 ` Roger Shimizu
2017-01-03 14:11 ` Roger Shimizu
2017-01-03 17:09 ` Rob Herring
2017-01-03 17:09 ` Rob Herring
2017-01-06 12:18 ` Roger Shimizu
2017-01-06 12:18 ` Roger Shimizu
2016-12-27 7:06 ` [PATCH v3 3/3] ARM: DT: add power-off support to linkstation lsgl and kuroboxpro Roger Shimizu
2016-12-27 7:06 ` Roger Shimizu
2017-01-07 15:04 ` [PATCH v4 0/2] make kurobox-pro be able to shutdown after device-tree migration Roger Shimizu
2017-01-07 15:04 ` Roger Shimizu
[not found] ` <20170107150451.17912-1-rogershimizu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-01-07 15:04 ` Roger Shimizu [this message]
2017-01-07 15:04 ` [PATCH v4 1/2] power: reset: add linkstation-reset driver Roger Shimizu
2017-01-08 17:02 ` Ryan Tandy
2017-01-08 17:02 ` Ryan Tandy
2017-01-09 3:31 ` Roger Shimizu
2017-01-09 3:31 ` Roger Shimizu
2017-01-09 5:43 ` Ryan Tandy
2017-01-09 5:43 ` Ryan Tandy
2017-01-18 12:08 ` Roger Shimizu
2017-01-18 12:08 ` Roger Shimizu
2017-01-19 4:43 ` Sebastian Reichel
2017-01-19 4:43 ` Sebastian Reichel
2017-01-26 15:28 ` Gregory CLEMENT
2017-01-26 15:28 ` Gregory CLEMENT
2017-01-26 15:33 ` Roger Shimizu
2017-01-26 15:33 ` Roger Shimizu
2017-01-27 9:15 ` Gregory CLEMENT
2017-01-27 9:15 ` Gregory CLEMENT
2017-01-07 15:04 ` [PATCH v4 2/2] ARM: DT: add power-off support to linkstation lsgl and kuroboxpro Roger Shimizu
2017-01-07 15:04 ` Roger Shimizu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170107150451.17912-2-rogershimizu@gmail.com \
--to=rogershimizu-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
--cc=andrew-g2DYL2Zd6BY@public.gmane.org \
--cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
--cc=hvr-mXXj517/zsQ@public.gmane.org \
--cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
--cc=linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=ryan-pRYBVO4bdZ33fQ9qLvQP4Q@public.gmane.org \
--cc=sylver.bruneau-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org \
--cc=tbm-R+vWnYXSFMfQT0dZR+AlfA@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.