summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-sa1100/h3xxx.c22
-rw-r--r--drivers/tty/serial/sa1100.c76
-rw-r--r--include/linux/platform_data/sa11x0-serial.h9
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