mirror of
https://github.com/torvalds/linux.git
synced 2024-12-21 18:42:44 +00:00
c227f127e3
The change switches NXP LPC32xx platforms to LPC32xx clock driver powered by common clock framework, this obsoletes mach-lpc32xx/clock.o legacy clock driver and thus it is removed. Legacy timer driver mach-lpc32xx/timer.o strictly depends on legacy clock support, but fortunately an existing LPC32xx clock source and clock event driver completely replaces it, and thus it can be removed as well. Noticeably platform UART driver directly operates on LPC32xx source control block registers, remove this dependency to avoid overlapping with common clock framework driver, also this guarantees that UART is working expectedly. Tested-by: Sylvain Lemieux <slemieux@tycoint.com> Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
128 lines
3.5 KiB
C
128 lines
3.5 KiB
C
/*
|
|
* arch/arm/mach-lpc32xx/serial.c
|
|
*
|
|
* Author: Kevin Wells <kevin.wells@nxp.com>
|
|
*
|
|
* Copyright (C) 2010 NXP Semiconductors
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/types.h>
|
|
#include <linux/serial.h>
|
|
#include <linux/serial_core.h>
|
|
#include <linux/serial_reg.h>
|
|
#include <linux/serial_8250.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/io.h>
|
|
|
|
#include <mach/hardware.h>
|
|
#include <mach/platform.h>
|
|
#include "common.h"
|
|
|
|
#define LPC32XX_SUART_FIFO_SIZE 64
|
|
|
|
struct uartinit {
|
|
char *uart_ck_name;
|
|
u32 ck_mode_mask;
|
|
void __iomem *pdiv_clk_reg;
|
|
resource_size_t mapbase;
|
|
};
|
|
|
|
static struct uartinit uartinit_data[] __initdata = {
|
|
{
|
|
.uart_ck_name = "uart5_ck",
|
|
.ck_mode_mask =
|
|
LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5),
|
|
.pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL,
|
|
.mapbase = LPC32XX_UART5_BASE,
|
|
},
|
|
{
|
|
.uart_ck_name = "uart3_ck",
|
|
.ck_mode_mask =
|
|
LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3),
|
|
.pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL,
|
|
.mapbase = LPC32XX_UART3_BASE,
|
|
},
|
|
{
|
|
.uart_ck_name = "uart4_ck",
|
|
.ck_mode_mask =
|
|
LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4),
|
|
.pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL,
|
|
.mapbase = LPC32XX_UART4_BASE,
|
|
},
|
|
{
|
|
.uart_ck_name = "uart6_ck",
|
|
.ck_mode_mask =
|
|
LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6),
|
|
.pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL,
|
|
.mapbase = LPC32XX_UART6_BASE,
|
|
},
|
|
};
|
|
|
|
void __init lpc32xx_serial_init(void)
|
|
{
|
|
u32 tmp, clkmodes = 0;
|
|
struct clk *clk;
|
|
unsigned int puart;
|
|
int i, j;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
|
|
clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
|
|
if (!IS_ERR(clk)) {
|
|
clk_enable(clk);
|
|
}
|
|
|
|
/* Setup UART clock modes for all UARTs, disable autoclock */
|
|
clkmodes |= uartinit_data[i].ck_mode_mask;
|
|
|
|
/* pre-UART clock divider set to 1 */
|
|
__raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg);
|
|
|
|
/*
|
|
* Force a flush of the RX FIFOs to work around a
|
|
* HW bug
|
|
*/
|
|
puart = uartinit_data[i].mapbase;
|
|
__raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
|
|
__raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
|
|
j = LPC32XX_SUART_FIFO_SIZE;
|
|
while (j--)
|
|
tmp = __raw_readl(
|
|
LPC32XX_UART_DLL_FIFO(puart));
|
|
__raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
|
|
}
|
|
|
|
/* This needs to be done after all UART clocks are setup */
|
|
__raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE);
|
|
for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
|
|
/* Force a flush of the RX FIFOs to work around a HW bug */
|
|
puart = uartinit_data[i].mapbase;
|
|
__raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
|
|
__raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
|
|
j = LPC32XX_SUART_FIFO_SIZE;
|
|
while (j--)
|
|
tmp = __raw_readl(LPC32XX_UART_DLL_FIFO(puart));
|
|
__raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
|
|
}
|
|
|
|
/* Disable IrDA pulsing support on UART6 */
|
|
tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
|
|
tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS;
|
|
__raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
|
|
|
|
/* Disable UART5->USB transparent mode or USB won't work */
|
|
tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
|
|
tmp &= ~LPC32XX_UART_U5_ROUTE_TO_USB;
|
|
__raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
|
|
}
|