summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/sa1100.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/sa1100.c')
-rw-r--r--drivers/tty/serial/sa1100.c76
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);