aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/mvebu-uart.c
diff options
context:
space:
mode:
authorMiquel Raynal <miquel.raynal@bootlin.com>2018-04-21 16:07:33 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-04-22 17:38:01 +0200
commit394e835145414f8633303b46fe938e10fda697c4 (patch)
treef4181eeecf9623e62375ef134862f9167dd4c9ec /drivers/tty/serial/mvebu-uart.c
parenttty: serial: msm_serial: Add support for suspend/resume (diff)
downloadlinux-dev-394e835145414f8633303b46fe938e10fda697c4.tar.xz
linux-dev-394e835145414f8633303b46fe938e10fda697c4.zip
serial: mvebu-uart: add suspend/resume support
Add suspend and resume hooks to save/restore the registers content during S2RAM operation. Also save/restore the oversampling rate register (OSAMP) as earlier stages already tuned that register to get a precise UART clock. Suggested-by: Allen Yan <yanwei@marvell.com> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/mvebu-uart.c')
-rw-r--r--drivers/tty/serial/mvebu-uart.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index 750e5645dc85..013b86a1044f 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -71,6 +71,8 @@
#define UART_BRDV 0x10
#define BRDV_BAUD_MASK 0x3FF
+#define UART_OSAMP 0x14
+
#define MVEBU_NR_UARTS 2
#define MVEBU_UART_TYPE "mvebu-uart"
@@ -108,6 +110,17 @@ struct mvebu_uart_driver_data {
struct uart_flags flags;
};
+/* Saved registers during suspend */
+struct mvebu_uart_pm_regs {
+ unsigned int rbr;
+ unsigned int tsh;
+ unsigned int ctrl;
+ unsigned int intr;
+ unsigned int stat;
+ unsigned int brdv;
+ unsigned int osamp;
+};
+
/* MVEBU UART driver structure */
struct mvebu_uart {
struct uart_port *port;
@@ -115,6 +128,9 @@ struct mvebu_uart {
int irq[UART_IRQ_COUNT];
unsigned char __iomem *nb;
struct mvebu_uart_driver_data *data;
+#if defined(CONFIG_PM)
+ struct mvebu_uart_pm_regs pm_regs;
+#endif /* CONFIG_PM */
};
static struct mvebu_uart *to_mvuart(struct uart_port *port)
@@ -719,6 +735,51 @@ static struct uart_driver mvebu_uart_driver = {
#endif
};
+#if defined(CONFIG_PM)
+static int mvebu_uart_suspend(struct device *dev)
+{
+ struct mvebu_uart *mvuart = dev_get_drvdata(dev);
+ struct uart_port *port = mvuart->port;
+
+ uart_suspend_port(&mvebu_uart_driver, port);
+
+ mvuart->pm_regs.rbr = readl(port->membase + UART_RBR(port));
+ mvuart->pm_regs.tsh = readl(port->membase + UART_TSH(port));
+ mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port));
+ mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port));
+ mvuart->pm_regs.stat = readl(port->membase + UART_STAT);
+ mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV);
+ mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP);
+
+ device_set_wakeup_enable(dev, true);
+
+ return 0;
+}
+
+static int mvebu_uart_resume(struct device *dev)
+{
+ struct mvebu_uart *mvuart = dev_get_drvdata(dev);
+ struct uart_port *port = mvuart->port;
+
+ writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port));
+ writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port));
+ writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port));
+ writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port));
+ writel(mvuart->pm_regs.stat, port->membase + UART_STAT);
+ writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV);
+ writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP);
+
+ uart_resume_port(&mvebu_uart_driver, port);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mvebu_uart_pm_ops = {
+ .suspend = mvebu_uart_suspend,
+ .resume = mvebu_uart_resume,
+};
+#endif /* CONFIG_PM */
+
static const struct of_device_id mvebu_uart_of_match[];
/* Counter to keep track of each UART port id when not using CONFIG_OF */
@@ -892,6 +953,9 @@ static struct platform_driver mvebu_uart_platform_driver = {
.name = "mvebu-uart",
.of_match_table = of_match_ptr(mvebu_uart_of_match),
.suppress_bind_attrs = true,
+#if defined(CONFIG_PM)
+ .pm = &mvebu_uart_pm_ops,
+#endif /* CONFIG_PM */
},
};