diff options
-rw-r--r-- | arch/arm/mach-sa1100/h3xxx.c | 22 | ||||
-rw-r--r-- | drivers/tty/serial/sa1100.c | 76 | ||||
-rw-r--r-- | include/linux/platform_data/sa11x0-serial.h | 9 |
3 files changed, 83 insertions, 24 deletions
diff --git a/arch/arm/mach-sa1100/h3xxx.c b/arch/arm/mach-sa1100/h3xxx.c index d685f03f51f3..9afa12b1a580 100644 --- a/arch/arm/mach-sa1100/h3xxx.c +++ b/arch/arm/mach-sa1100/h3xxx.c @@ -96,27 +96,11 @@ static void h3xxx_uart_pm(struct uart_port *port, u_int state, u_int oldstate) } } -/* - * Enable/Disable wake up events for this serial port. - * Obviously, we only support this on the normal COM port. - */ -static int h3xxx_uart_set_wake(struct uart_port *port, u_int enable) -{ - int err = -EINVAL; - - if (port->mapbase == _Ser3UTCR0) { - if (enable) - PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */ - else - PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */ - err = 0; - } - return err; -} - static struct sa1100_port_fns h3xxx_port_fns __initdata = { .pm = h3xxx_uart_pm, - .set_wake = h3xxx_uart_set_wake, + .wake = { + [0] = SA11X0_WAKE_CTS | SA11X0_WAKE_DCD, + }, }; static struct gpiod_lookup_table h3xxx_uart3_gpio_table = { diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index 4c0052f37cbf..231f60b41e3c 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -76,6 +76,7 @@ struct sa1100_port { struct timer_list timer; unsigned int old_status; struct mctrl_gpios *gpios; + unsigned wake; }; /* @@ -649,16 +650,17 @@ static void __init sa1100_init_ports(void) void sa1100_register_uart_fns(struct sa1100_port_fns *fns) { + unsigned int i; + if (fns->get_mctrl) sa1100_pops.get_mctrl = fns->get_mctrl; if (fns->set_mctrl) sa1100_pops.set_mctrl = fns->set_mctrl; sa1100_pops.pm = fns->pm; - /* - * FIXME: fns->set_wake is unused - this should be called from - * the suspend() callback if device_may_wakeup(dev)) is set. - */ + + for (i = 0; i < NR_PORTS; i++) + sa1100_ports[i].wake = fns->wake[i]; } void __init sa1100_register_uart(int idx, int port) @@ -831,19 +833,83 @@ static struct uart_driver sa1100_reg = { .cons = SA1100_CONSOLE, }; +static unsigned int sa1100_translate_mctrl_wake_mask(unsigned int wake_bits) +{ + unsigned int wake = 0; + + if (wake_bits & SA11X0_WAKE_CTS) + wake |= BIT(UART_GPIO_CTS); + if (wake_bits & SA11X0_WAKE_DCD) + wake |= BIT(UART_GPIO_DCD); + if (wake_bits & SA11X0_WAKE_DSR) + wake |= BIT(UART_GPIO_DSR); + if (wake_bits & SA11X0_WAKE_RI) + wake |= BIT(UART_GPIO_RI); + + return wake; +} + static int sa1100_serial_suspend(struct platform_device *dev, pm_message_t state) { struct sa1100_port *sport = platform_get_drvdata(dev); + unsigned int i, enabled = 0, wake; + int ret; + + wake = sa1100_translate_mctrl_wake_mask(sport->wake); + + for (i = 0; i < UART_GPIO_MAX; i++) { + struct gpio_desc *g; + int irq; + + if (!(wake & BIT(i))) + continue; + + g = mctrl_gpio_to_gpiod(sport->gpios, i); + if (!g) + continue; + + irq = gpiod_to_irq(g); + if (irq > 0) { + ret = enable_irq_wake(irq); + if (ret) + goto disable; + } + + enabled |= BIT(i); + } if (sport) uart_suspend_port(&sa1100_reg, &sport->port); return 0; + + disable: + for (i = 0; i < UART_GPIO_MAX; i++) + if (enabled & BIT(i)) + mctrl_gpio_disable_wake(sport->gpios, i); + return ret; } static int sa1100_serial_resume(struct platform_device *dev) { struct sa1100_port *sport = platform_get_drvdata(dev); + unsigned int i, wake = sa1100_translate_mctrl_wake_mask(sport->wake); + + for (i = 0; i < UART_GPIO_MAX; i++) { + struct gpio_desc *g; + int irq; + + if (!(wake & BIT(i))) + continue; + + g = mctrl_gpio_to_gpiod(sport->gpios, i); + if (!g) + continue; + + irq = gpiod_to_irq(g); + if (irq > 0) + disable_irq_wake(irq); + } if (sport) uart_resume_port(&sa1100_reg, &sport->port); @@ -872,6 +938,8 @@ static int sa1100_serial_add_one_port(struct sa1100_port *sport, struct platform sport->gpios = NULL; } + device_init_wakeup(sport->port.dev, !!sport->wake); + platform_set_drvdata(dev, sport); return uart_add_one_port(&sa1100_reg, &sport->port); diff --git a/include/linux/platform_data/sa11x0-serial.h b/include/linux/platform_data/sa11x0-serial.h index 8b79ab08af45..319fcc566626 100644 --- a/include/linux/platform_data/sa11x0-serial.h +++ b/include/linux/platform_data/sa11x0-serial.h @@ -12,6 +12,13 @@ struct uart_port; struct uart_info; +enum { + SA11X0_WAKE_CTS = BIT(0), + SA11X0_WAKE_DCD = BIT(1), + SA11X0_WAKE_DSR = BIT(2), + SA11X0_WAKE_RI = BIT(3), +}; + /* * This is a temporary structure for registering these * functions; it is intended to be discarded after boot. @@ -20,7 +27,7 @@ struct sa1100_port_fns { void (*set_mctrl)(struct uart_port *, u_int); u_int (*get_mctrl)(struct uart_port *); void (*pm)(struct uart_port *, u_int, u_int); - int (*set_wake)(struct uart_port *, u_int); + unsigned wake[3]; }; #ifdef CONFIG_SERIAL_SA1100 |