diff options
Diffstat (limited to 'drivers/tty/serial/sa1100.c')
-rw-r--r-- | drivers/tty/serial/sa1100.c | 76 |
1 files changed, 72 insertions, 4 deletions
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); |