summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2012-08-01 17:50:18 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2012-08-01 17:50:18 +0200
commita934d16a2aa402f9f417f8a533ea80abcf1d2771 (patch)
tree3ad455d393a0ef35b44ea2d6aa2ade676801250e /drivers
parent33838de7a241242c40f23fa3f95939d29c78544d (diff)
parentd65926656c9e51419ec491a48f71017e3c9759cd (diff)
downloadbarebox-a934d16a2aa402f9f417f8a533ea80abcf1d2771.tar.gz
barebox-a934d16a2aa402f9f417f8a533ea80abcf1d2771.tar.xz
Merge branch 'for-next/samsung'
Conflicts: arch/arm/Makefile arch/arm/mach-samsung/Makefile arch/arm/mach-samsung/include/mach/s5pcxx-iomap.h
Diffstat (limited to 'drivers')
-rw-r--r--drivers/serial/Kconfig4
-rw-r--r--drivers/serial/serial_s3c.c71
2 files changed, 42 insertions, 33 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index a9383da9d7..2b9a9b941a 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -78,9 +78,13 @@ config DRIVER_SERIAL_PL010
help
Enable this to get support for AMBA PL010 based serial devices
+config DRIVER_SERIAL_S3C_IMPROVED
+ bool
+
config DRIVER_SERIAL_S3C
bool "Samsung S3C serial driver"
depends on ARCH_SAMSUNG
+ select DRIVER_SERIAL_S3C_IMPROVED if (CPU_S5PC110 || CPU_S5PV210)
default y
help
Say Y here if you want to use the CONS on a Samsung S3C CPU
diff --git a/drivers/serial/serial_s3c.c b/drivers/serial/serial_s3c.c
index 7a9b355704..0a7b137d19 100644
--- a/drivers/serial/serial_s3c.c
+++ b/drivers/serial/serial_s3c.c
@@ -31,6 +31,8 @@
/* Note: Offsets are for little endian access */
#define ULCON 0x00 /* line control */
#define UCON 0x04 /* UART control */
+# define UCON_SET_CLK_SRC(x) (((x) & 0x03) << 10)
+# define UCON_GET_CLK_SRC(x) (((x) >> 10) & 0x03)
#define UFCON 0x08 /* FIFO control */
#define UMCON 0x0c /* modem control */
#define UTRSTAT 0x10 /* Rx/Tx status */
@@ -40,17 +42,8 @@
#define UTXH 0x20 /* transmitt */
#define URXH 0x24 /* receive */
#define UBRDIV 0x28 /* baudrate generator */
-#ifdef S3C_UART_HAS_UBRDIVSLOT
-# define UBRDIVSLOT 0x2c /* baudrate slot generator */
-#endif
-#ifdef S3C_UART_HAS_UINTM
-# define UINTM 0x38 /* interrupt mask register */
-#endif
-
-#ifndef S3C_UART_CLKSEL
-/* Use pclk */
-# define S3C_UART_CLKSEL 0
-#endif
+#define UBRDIVSLOT 0x2c /* baudrate slot generator */
+#define UINTM 0x38 /* interrupt mask register */
struct s3c_uart {
void __iomem *regs;
@@ -59,14 +52,23 @@ struct s3c_uart {
#define to_s3c_uart(c) container_of(c, struct s3c_uart, cdev)
+/* each architecture has a preferred reference clock for its UARTs */
+static unsigned s3c_select_arch_input_clock(void)
+{
+ /* S3C24xx: 0=2=PCLK, 1=UEXTCLK, 3=FCLK/n */
+ if (IS_ENABLED(CONFIG_ARCH_S3C24xx))
+ return 0; /* use the internal PCLK */
+ /* S5PCxx: 0=PCLK, 1=SCLK_UART */
+ if (IS_ENABLED(CONFIG_ARCH_S5PCxx))
+ return 0; /* use the internal PCLK */
+}
+
static unsigned s3c_get_arch_uart_input_clock(void __iomem *base)
{
unsigned reg = readw(base + UCON);
- reg = (reg >> 10) & 0x3;
- return s3c_get_uart_clk(reg);
+ return s3c_get_uart_clk(UCON_GET_CLK_SRC(reg));
}
-#ifdef S3C_UART_HAS_UBRDIVSLOT
/*
* This table takes the fractional value of the baud divisor and gives
* the recommended setting for the UDIVSLOT register. Refer the datasheet
@@ -76,7 +78,6 @@ static const uint16_t udivslot_table[] __maybe_unused = {
0x0000, 0x0080, 0x0808, 0x0888, 0x2222, 0x4924, 0x4A52, 0x54AA,
0x5555, 0xD555, 0xD5D5, 0xDDD5, 0xDDDD, 0xDFDD, 0xDFDF, 0xFFDF,
};
-#endif
static int s3c_serial_setbaudrate(struct console_device *cdev, int baudrate)
{
@@ -84,10 +85,11 @@ static int s3c_serial_setbaudrate(struct console_device *cdev, int baudrate)
void __iomem *base = priv->regs;
unsigned val;
-#ifdef S3C_UART_HAS_UBRDIVSLOT
- val = s3c_get_arch_uart_input_clock(base) / baudrate;
- writew(udivslot_table[val & 15], base + UBRDIVSLOT);
-#endif
+ if (IS_ENABLED(CONFIG_DRIVER_SERIAL_S3C_IMPROVED)) {
+ val = s3c_get_arch_uart_input_clock(base) / baudrate;
+ writew(udivslot_table[val & 15], base + UBRDIVSLOT);
+ }
+
val = s3c_get_arch_uart_input_clock(base) / (16 * baudrate) - 1;
writew(val, base + UBRDIV);
@@ -106,20 +108,23 @@ static int s3c_serial_init_port(struct console_device *cdev)
/* Normal,No parity,1 stop,8 bit */
writeb(0x03, base + ULCON);
- /* tx=level,rx=edge,disable timeout int.,enable rx error int.,
- * normal, interrupt or polling, no pre-divider */
- writew(0x0245 | ((S3C_UART_CLKSEL) << 10), base + UCON);
-
-#ifdef S3C_UART_HAS_UINTM
- /* 'interrupt or polling mode' for both directions */
- writeb(0xf, base + UINTM);
-#endif
-
-#ifdef CONFIG_DRIVER_SERIAL_S3C_AUTOSYNC
- writeb(0x10, base + UMCON); /* enable auto flow control */
-#else
- writeb(0x01, base + UMCON); /* RTS up */
-#endif
+ /*
+ * S3C2440 SoC:
+ * - no clock divider
+ * all SoCs:
+ * - enable receive and transmit mode
+ */
+ writew(0x0005 | UCON_SET_CLK_SRC(s3c_select_arch_input_clock()),
+ base + UCON);
+
+ if (IS_ENABLED(CONFIG_DRIVER_SERIAL_S3C_IMPROVED))
+ /* 'interrupt or polling mode' for both directions */
+ writeb(0xf, base + UINTM);
+
+ if (IS_ENABLED(CONFIG_DRIVER_SERIAL_S3C_AUTOSYNC))
+ writeb(0x10, base + UMCON); /* enable auto flow control */
+ else
+ writeb(0x01, base + UMCON); /* RTS up */
return 0;
}