Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * arch/arm/mach-lpc32xx/serial.c
0004  *
0005  * Author: Kevin Wells <kevin.wells@nxp.com>
0006  *
0007  * Copyright (C) 2010 NXP Semiconductors
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/types.h>
0012 #include <linux/serial.h>
0013 #include <linux/serial_core.h>
0014 #include <linux/serial_reg.h>
0015 #include <linux/serial_8250.h>
0016 #include <linux/clk.h>
0017 #include <linux/io.h>
0018 
0019 #include "lpc32xx.h"
0020 #include "common.h"
0021 
0022 #define LPC32XX_SUART_FIFO_SIZE 64
0023 
0024 struct uartinit {
0025     char *uart_ck_name;
0026     u32 ck_mode_mask;
0027     void __iomem *pdiv_clk_reg;
0028     resource_size_t mapbase;
0029 };
0030 
0031 static struct uartinit uartinit_data[] __initdata = {
0032     {
0033         .uart_ck_name = "uart5_ck",
0034         .ck_mode_mask =
0035             LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5),
0036         .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL,
0037         .mapbase = LPC32XX_UART5_BASE,
0038     },
0039     {
0040         .uart_ck_name = "uart3_ck",
0041         .ck_mode_mask =
0042             LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3),
0043         .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL,
0044         .mapbase = LPC32XX_UART3_BASE,
0045     },
0046     {
0047         .uart_ck_name = "uart4_ck",
0048         .ck_mode_mask =
0049             LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4),
0050         .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL,
0051         .mapbase = LPC32XX_UART4_BASE,
0052     },
0053     {
0054         .uart_ck_name = "uart6_ck",
0055         .ck_mode_mask =
0056             LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6),
0057         .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL,
0058         .mapbase = LPC32XX_UART6_BASE,
0059     },
0060 };
0061 
0062 /* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */
0063 void lpc32xx_loopback_set(resource_size_t mapbase, int state)
0064 {
0065     int bit;
0066     u32 tmp;
0067 
0068     switch (mapbase) {
0069     case LPC32XX_HS_UART1_BASE:
0070         bit = 0;
0071         break;
0072     case LPC32XX_HS_UART2_BASE:
0073         bit = 1;
0074         break;
0075     case LPC32XX_HS_UART7_BASE:
0076         bit = 6;
0077         break;
0078     default:
0079         WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase);
0080         return;
0081     }
0082 
0083     tmp = readl(LPC32XX_UARTCTL_CLOOP);
0084     if (state)
0085         tmp |= (1 << bit);
0086     else
0087         tmp &= ~(1 << bit);
0088     writel(tmp, LPC32XX_UARTCTL_CLOOP);
0089 }
0090 EXPORT_SYMBOL_GPL(lpc32xx_loopback_set);
0091 
0092 void __init lpc32xx_serial_init(void)
0093 {
0094     u32 tmp, clkmodes = 0;
0095     struct clk *clk;
0096     unsigned int puart;
0097     int i, j;
0098 
0099     for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
0100         clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
0101         if (!IS_ERR(clk)) {
0102             clk_enable(clk);
0103         }
0104 
0105         /* Setup UART clock modes for all UARTs, disable autoclock */
0106         clkmodes |= uartinit_data[i].ck_mode_mask;
0107 
0108         /* pre-UART clock divider set to 1 */
0109         __raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg);
0110 
0111         /*
0112          * Force a flush of the RX FIFOs to work around a
0113          * HW bug
0114          */
0115         puart = uartinit_data[i].mapbase;
0116         __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
0117         __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
0118         j = LPC32XX_SUART_FIFO_SIZE;
0119         while (j--)
0120             tmp = __raw_readl(
0121                 LPC32XX_UART_DLL_FIFO(puart));
0122         __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
0123     }
0124 
0125     /* This needs to be done after all UART clocks are setup */
0126     __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE);
0127     for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
0128         /* Force a flush of the RX FIFOs to work around a HW bug */
0129         puart = uartinit_data[i].mapbase;
0130         __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
0131         __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
0132         j = LPC32XX_SUART_FIFO_SIZE;
0133         while (j--)
0134             tmp = __raw_readl(LPC32XX_UART_DLL_FIFO(puart));
0135         __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
0136     }
0137 
0138     /* Disable IrDA pulsing support on UART6 */
0139     tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
0140     tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS;
0141     __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
0142 
0143     /* Disable UART5->USB transparent mode or USB won't work */
0144     tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
0145     tmp &= ~LPC32XX_UART_U5_ROUTE_TO_USB;
0146     __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
0147 }