@ -1,5 +1,5 @@
/*
* QNAP Turbo NAS Board power off
* QNAP Turbo NAS Board power off . Can also be used on Synology devices .
*
* Copyright ( C ) 2012 Andrew Lunn < andrew @ lunn . ch >
*
@ -25,17 +25,43 @@
# define UART1_REG(x) (base + ((UART_##x) << 2))
struct power_off_cfg {
u32 baud ;
char cmd ;
} ;
static const struct power_off_cfg qnap_power_off_cfg = {
. baud = 19200 ,
. cmd = ' A ' ,
} ;
static const struct power_off_cfg synology_power_off_cfg = {
. baud = 9600 ,
. cmd = ' 1 ' ,
} ;
static const struct of_device_id qnap_power_off_of_match_table [ ] = {
{ . compatible = " qnap,power-off " ,
. data = & qnap_power_off_cfg ,
} ,
{ . compatible = " synology,power-off " ,
. data = & synology_power_off_cfg ,
} ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , qnap_power_off_of_match_table ) ;
static void __iomem * base ;
static unsigned long tclk ;
static const struct power_off_cfg * cfg ;
static void qnap_power_off ( void )
{
/* 19200 baud divisor */
const unsigned divisor = ( ( tclk + ( 8 * 19200 ) ) / ( 16 * 19200 ) ) ;
const unsigned divisor = ( ( tclk + ( 8 * cfg - > baud ) ) / ( 16 * cfg - > baud ) ) ;
pr_err ( " %s: triggering power-off... \n " , __func__ ) ;
/* hijack UART1 and reset into sane state (19200,8n1) */
/* hijack UART1 and reset into sane state */
writel ( 0x83 , UART1_REG ( LCR ) ) ;
writel ( divisor & 0xff , UART1_REG ( DLL ) ) ;
writel ( ( divisor > > 8 ) & 0xff , UART1_REG ( DLM ) ) ;
@ -44,16 +70,21 @@ static void qnap_power_off(void)
writel ( 0x00 , UART1_REG ( FCR ) ) ;
writel ( 0x00 , UART1_REG ( MCR ) ) ;
/* send the power-off command 'A' to PIC */
writel ( ' A ' , UART1_REG ( TX ) ) ;
/* send the power-off command to PIC */
writel ( cfg - > cmd , UART1_REG ( TX ) ) ;
}
static int qnap_power_off_probe ( struct platform_device * pdev )
{
struct device_node * np = pdev - > dev . of_node ;
struct resource * res ;
struct clk * clk ;
char symname [ KSYM_NAME_LEN ] ;
const struct of_device_id * match =
of_match_node ( qnap_power_off_of_match_table , np ) ;
cfg = match - > data ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " Missing resource " ) ;
@ -94,12 +125,6 @@ static int qnap_power_off_remove(struct platform_device *pdev)
return 0 ;
}
static const struct of_device_id qnap_power_off_of_match_table [ ] = {
{ . compatible = " qnap,power-off " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , qnap_power_off_of_match_table ) ;
static struct platform_driver qnap_power_off_driver = {
. probe = qnap_power_off_probe ,
. remove = qnap_power_off_remove ,