/* * Copyright (C) ST-Ericsson SA 2011 * * Author: Arun R Murthy , * Jonas Aaberg for ST-Ericsson * * License terms: GNU General Public License (GPL) version 2 */ #include #include #include #include #include #include #include #include "pm/context.h" #ifdef CONFIG_UX500_CONTEXT #define UX500_NR_UARTS 3 static struct { struct clk *uart_clk; void __iomem *base; u32 dr; u32 rsr_err; u32 dma_wm; u32 timeout; /* fr */ u32 lcrh_rx; u32 ilpr; u32 ibrd; u32 fbrd; u32 lcrh_tx; u32 cr; u32 ifls; u32 imsc; /* ris */ /* mis */ /* icr */ u32 dmacr; u32 xfcr; u32 xon1; u32 xon2; u32 xoff1; u32 xoff2; u32 itcr; u32 itip; u32 itop; u32 tdr; u32 abcr; /* absr */ /* abfmt */ /* abdr */ /* abdfr */ /* abmr */ u32 abimsc; /* abris */ /* abmis */ /* abicr */ /* id_product_h_xy */ /* id_provider */ /* periphid0 */ /* periphid1 */ /* periphid2 */ /* periphid3 */ /* pcellid0 */ /* pcellid1 */ /* pcellid2 */ /* pcellid3 */ } context_uart[UX500_NR_UARTS]; static void save_uart(void) { int i; for (i = 0; i < UX500_NR_UARTS; i++) { /* * No need to store the UART register values * for the port which is already disabled the clock * other than the console port. */ context_uart[i].cr = readl(context_uart[i].base + UART011_CR); if ((!context_uart[i].cr) && (i != CONFIG_UX500_DEBUG_UART)) continue; clk_enable(context_uart[i].uart_clk); context_uart[i].dr = readl(context_uart[i].base + UART01x_DR); context_uart[i].rsr_err = readl(context_uart[i].base + UART01x_RSR); context_uart[i].dma_wm = readl(context_uart[i].base + ST_UART011_DMAWM); context_uart[i].timeout = readl(context_uart[i].base + ST_UART011_TIMEOUT); context_uart[i].lcrh_rx = readl(context_uart[i].base + ST_UART011_LCRH_RX); context_uart[i].ilpr = readl(context_uart[i].base + UART01x_ILPR); context_uart[i].ibrd = readl(context_uart[i].base + UART011_IBRD); context_uart[i].fbrd = readl(context_uart[i].base + UART011_FBRD); context_uart[i].lcrh_tx = readl(context_uart[i].base + ST_UART011_LCRH_TX); context_uart[i].cr = readl(context_uart[i].base + UART011_CR); context_uart[i].ifls = readl(context_uart[i].base + UART011_IFLS); context_uart[i].imsc = readl(context_uart[i].base + UART011_IMSC); context_uart[i].dmacr = readl(context_uart[i].base + UART011_DMACR); context_uart[i].xfcr = readl(context_uart[i].base + ST_UART011_XFCR); context_uart[i].xon1 = readl(context_uart[i].base + ST_UART011_XON1); context_uart[i].xon2 = readl(context_uart[i].base + ST_UART011_XON2); context_uart[i].xoff1 = readl(context_uart[i].base + ST_UART011_XOFF1); context_uart[i].xoff2 = readl(context_uart[i].base + ST_UART011_XOFF2); context_uart[i].itcr = readl(context_uart[i].base + ST_UART011_ITCR); context_uart[i].itip = readl(context_uart[i].base + ST_UART011_ITIP); context_uart[i].itop = readl(context_uart[i].base + ST_UART011_ITOP); context_uart[i].tdr = readl(context_uart[i].base + ST_UART011_TDR); context_uart[i].abcr = readl(context_uart[i].base + ST_UART011_ABCR); context_uart[i].abimsc = readl(context_uart[i].base + ST_UART011_ABIMSC); clk_disable(context_uart[i].uart_clk); } } static void restore_uart(void) { int i, cnt; for (i = 0; i < UX500_NR_UARTS; i++) { /* * No need to restore the UART register values * for the port which is already disabled the clock * other than the console port. */ if ((!context_uart[i].cr) && (i != CONFIG_UX500_DEBUG_UART)) continue; clk_enable(context_uart[i].uart_clk); writel(context_uart[i].dr, context_uart[i].base + UART01x_DR); writel(context_uart[i].rsr_err, context_uart[i].base + UART01x_RSR); writel(context_uart[i].dma_wm, context_uart[i].base + ST_UART011_DMAWM); writel(context_uart[i].timeout, context_uart[i].base + ST_UART011_TIMEOUT); writel(context_uart[i].lcrh_rx, context_uart[i].base + ST_UART011_LCRH_RX); writel(context_uart[i].ilpr, context_uart[i].base + UART01x_ILPR); writel(context_uart[i].ibrd, context_uart[i].base + UART011_IBRD); writel(context_uart[i].fbrd, context_uart[i].base + UART011_FBRD); /* * Wait 10 PCLKs before writing LCRH_TX register, * to get this delay write read only register 10-3 * times, as already there are 3 writes after * ST_UART011_LCRH_RX */ for (cnt = 0; cnt < 7; cnt++) writew(0xff, context_uart[i].base + UART011_MIS); writel(context_uart[i].lcrh_tx, context_uart[i].base + ST_UART011_LCRH_TX); writel(context_uart[i].cr, context_uart[i].base + UART011_CR); writel(context_uart[i].ifls, context_uart[i].base + UART011_IFLS); writel(context_uart[i].imsc, context_uart[i].base + UART011_IMSC); writel(context_uart[i].dmacr, context_uart[i].base + UART011_DMACR); writel(context_uart[i].xfcr, context_uart[i].base + ST_UART011_XFCR); writel(context_uart[i].xon1, context_uart[i].base + ST_UART011_XON1); writel(context_uart[i].xon2, context_uart[i].base + ST_UART011_XON2); writel(context_uart[i].xoff1, context_uart[i].base + ST_UART011_XOFF1); writel(context_uart[i].xoff2, context_uart[i].base + ST_UART011_XOFF2); writel(context_uart[i].itcr, context_uart[i].base + ST_UART011_ITCR); writel(context_uart[i].itip, context_uart[i].base + ST_UART011_ITIP); writel(context_uart[i].abcr, context_uart[i].base + ST_UART011_ABCR); writel(context_uart[i].itop, context_uart[i].base + ST_UART011_ITOP); writel(context_uart[i].tdr, context_uart[i].base + ST_UART011_TDR); writel(context_uart[i].abimsc, context_uart[i].base + ST_UART011_ABIMSC); clk_disable(context_uart[i].uart_clk); } } static int uart_context_notifier_call(struct notifier_block *this, unsigned long event, void *data) { switch (event) { case CONTEXT_APE_SAVE: save_uart(); break; case CONTEXT_APE_RESTORE: restore_uart(); break; } return NOTIFY_OK; } static struct notifier_block uart_context_notifier = { .notifier_call = uart_context_notifier_call, }; static void uart_context_notifier_init(void) { context_uart[0].base = ioremap(U8500_UART0_BASE, SZ_4K); context_uart[1].base = ioremap(U8500_UART1_BASE, SZ_4K); context_uart[2].base = ioremap(U8500_UART2_BASE, SZ_4K); context_uart[0].uart_clk = clk_get_sys("uart0", NULL); if (IS_ERR(context_uart[0].uart_clk)) { printk(KERN_ERR"%s:unable to get clk-uart0\n", __func__); return; } context_uart[1].uart_clk = clk_get_sys("uart1", NULL); if (IS_ERR(context_uart[1].uart_clk)) { printk(KERN_ERR"%s:unable to get clk-uart1\n", __func__); return; } context_uart[2].uart_clk = clk_get_sys("uart2", NULL); if (IS_ERR(context_uart[2].uart_clk)) { printk(KERN_ERR"%s:unable to get clk-uart2\n", __func__); return; } WARN_ON(context_ape_notifier_register(&uart_context_notifier)); } #else static void uart_context_notifier_init(void) { } #endif void __init db8500_uart_init(void) { uart_context_notifier_init(); }