Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Power: Reset: Generalize qnap-poweroff to work on Synology devices.

The Synology NAS devices use a very similar mechanism to QNAP NAS
devices to power off. Both send a single charactor command to a PIC,
over the second serial port. However the baud rate and the command
differ. Generalize the driver to support this.

Signed-off-by: Ben Peddell <klightspeed@killerwolves.net>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Acked-by: Jason Cooper <jason@lakedaemon.net>
Cc: Anton Vorontsov <anton@enomsg.org>
Cc: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Jason Cooper <jason@lakedaemon.net>

authored by

Andrew Lunn and committed by
Jason Cooper
200c0a3e ff1f0018

+41 -13
+4 -1
Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
··· 6 6 microcontroller to turn the power off. This driver adds a handler to 7 7 pm_power_off which is called to turn the power off. 8 8 9 + Synology NAS devices use a similar scheme, but a different baud rate, 10 + 9600, and a different character, '1'. 11 + 9 12 Required Properties: 10 - - compatible: Should be "qnap,power-off" 13 + - compatible: Should be "qnap,power-off" or "synology,power-off" 11 14 12 15 - reg: Address and length of the register set for UART1 13 16 - clocks: tclk clock
+37 -12
drivers/power/reset/qnap-poweroff.c
··· 1 1 /* 2 - * QNAP Turbo NAS Board power off 2 + * QNAP Turbo NAS Board power off. Can also be used on Synology devices. 3 3 * 4 4 * Copyright (C) 2012 Andrew Lunn <andrew@lunn.ch> 5 5 * ··· 25 25 26 26 #define UART1_REG(x) (base + ((UART_##x) << 2)) 27 27 28 + struct power_off_cfg { 29 + u32 baud; 30 + char cmd; 31 + }; 32 + 33 + static const struct power_off_cfg qnap_power_off_cfg = { 34 + .baud = 19200, 35 + .cmd = 'A', 36 + }; 37 + 38 + static const struct power_off_cfg synology_power_off_cfg = { 39 + .baud = 9600, 40 + .cmd = '1', 41 + }; 42 + 43 + static const struct of_device_id qnap_power_off_of_match_table[] = { 44 + { .compatible = "qnap,power-off", 45 + .data = &qnap_power_off_cfg, 46 + }, 47 + { .compatible = "synology,power-off", 48 + .data = &synology_power_off_cfg, 49 + }, 50 + {} 51 + }; 52 + MODULE_DEVICE_TABLE(of, qnap_power_off_of_match_table); 53 + 28 54 static void __iomem *base; 29 55 static unsigned long tclk; 56 + static const struct power_off_cfg *cfg; 30 57 31 58 static void qnap_power_off(void) 32 59 { 33 - /* 19200 baud divisor */ 34 - const unsigned divisor = ((tclk + (8 * 19200)) / (16 * 19200)); 60 + const unsigned divisor = ((tclk + (8 * cfg->baud)) / (16 * cfg->baud)); 35 61 36 62 pr_err("%s: triggering power-off...\n", __func__); 37 63 38 - /* hijack UART1 and reset into sane state (19200,8n1) */ 64 + /* hijack UART1 and reset into sane state */ 39 65 writel(0x83, UART1_REG(LCR)); 40 66 writel(divisor & 0xff, UART1_REG(DLL)); 41 67 writel((divisor >> 8) & 0xff, UART1_REG(DLM)); ··· 70 44 writel(0x00, UART1_REG(FCR)); 71 45 writel(0x00, UART1_REG(MCR)); 72 46 73 - /* send the power-off command 'A' to PIC */ 74 - writel('A', UART1_REG(TX)); 47 + /* send the power-off command to PIC */ 48 + writel(cfg->cmd, UART1_REG(TX)); 75 49 } 76 50 77 51 static int qnap_power_off_probe(struct platform_device *pdev) 78 52 { 53 + struct device_node *np = pdev->dev.of_node; 79 54 struct resource *res; 80 55 struct clk *clk; 81 56 char symname[KSYM_NAME_LEN]; 57 + 58 + const struct of_device_id *match = 59 + of_match_node(qnap_power_off_of_match_table, np); 60 + cfg = match->data; 82 61 83 62 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 84 63 if (!res) { ··· 124 93 pm_power_off = NULL; 125 94 return 0; 126 95 } 127 - 128 - static const struct of_device_id qnap_power_off_of_match_table[] = { 129 - { .compatible = "qnap,power-off", }, 130 - {} 131 - }; 132 - MODULE_DEVICE_TABLE(of, qnap_power_off_of_match_table); 133 96 134 97 static struct platform_driver qnap_power_off_driver = { 135 98 .probe = qnap_power_off_probe,