Commit 73e55cb3 authored by Ben Dooks's avatar Ben Dooks Committed by Russell King

[ARM] 3639/1: S3C2412: serial port support

Patch from Ben Dooks

Serial port support for the on-board UART blocks
on the Samsung S3C2412 and S3C2413 UARTs.
Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 736855f0
......@@ -354,21 +354,24 @@ config SERIAL_CLPS711X_CONSOLE
kernel at boot time.)
config SERIAL_S3C2410
tristate "Samsung S3C2410 Serial port support"
tristate "Samsung S3C2410/S3C2440/S3C2442/S3C2412 Serial port support"
depends on ARM && ARCH_S3C2410
select SERIAL_CORE
help
Support for the on-chip UARTs on the Samsung S3C2410X CPU,
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
provide all of these ports, depending on how the serial port
pins are configured.
Currently this driver supports the UARTS on the S3C2410, S3C2440,
S3C2442, S3C2412 and S3C2413 CPUs.
config SERIAL_S3C2410_CONSOLE
bool "Support for console on S3C2410 serial port"
depends on SERIAL_S3C2410=y
select SERIAL_CORE_CONSOLE
help
Allow selection of the S3C2410 on-board serial ports for use as
Allow selection of the S3C24XX on-board serial ports for use as
an virtual console.
Even if you say Y here, the currently visible virtual console
......
......@@ -872,6 +872,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
return "S3C2410";
case PORT_S3C2440:
return "S3C2440";
case PORT_S3C2412:
return "S3C2412";
default:
return NULL;
}
......@@ -1528,6 +1530,141 @@ static inline void s3c2440_serial_exit(void)
#define s3c2440_uart_inf_at NULL
#endif /* CONFIG_CPU_S3C2440 */
#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
static int s3c2412_serial_setsource(struct uart_port *port,
struct s3c24xx_uart_clksrc *clk)
{
unsigned long ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~S3C2412_UCON_CLKMASK;
if (strcmp(clk->name, "uclk") == 0)
ucon |= S3C2440_UCON_UCLK;
else if (strcmp(clk->name, "pclk") == 0)
ucon |= S3C2440_UCON_PCLK;
else if (strcmp(clk->name, "usysclk") == 0)
ucon |= S3C2412_UCON_USYSCLK;
else {
printk(KERN_ERR "unknown clock source %s\n", clk->name);
return -EINVAL;
}
wr_regl(port, S3C2410_UCON, ucon);
return 0;
}
static int s3c2412_serial_getsource(struct uart_port *port,
struct s3c24xx_uart_clksrc *clk)
{
unsigned long ucon = rd_regl(port, S3C2410_UCON);
switch (ucon & S3C2412_UCON_CLKMASK) {
case S3C2412_UCON_UCLK:
clk->divisor = 1;
clk->name = "uclk";
break;
case S3C2412_UCON_PCLK:
case S3C2412_UCON_PCLK2:
clk->divisor = 1;
clk->name = "pclk";
break;
case S3C2412_UCON_USYSCLK:
clk->divisor = 1;
clk->name = "usysclk";
break;
}
return 0;
}
static int s3c2412_serial_resetport(struct uart_port *port,
struct s3c2410_uartcfg *cfg)
{
unsigned long ucon = rd_regl(port, S3C2410_UCON);
dbg("%s: port=%p (%08lx), cfg=%p\n",
__FUNCTION__, port, port->mapbase, cfg);
/* ensure we don't change the clock settings... */
ucon &= S3C2412_UCON_CLKMASK;
wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
wr_regl(port, S3C2410_ULCON, cfg->ulcon);
/* reset both fifos */
wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
wr_regl(port, S3C2410_UFCON, cfg->ufcon);
return 0;
}
static struct s3c24xx_uart_info s3c2412_uart_inf = {
.name = "Samsung S3C2412 UART",
.type = PORT_S3C2412,
.fifosize = 64,
.rx_fifomask = S3C2440_UFSTAT_RXMASK,
.rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
.rx_fifofull = S3C2440_UFSTAT_RXFULL,
.tx_fifofull = S3C2440_UFSTAT_TXFULL,
.tx_fifomask = S3C2440_UFSTAT_TXMASK,
.tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
.get_clksrc = s3c2412_serial_getsource,
.set_clksrc = s3c2412_serial_setsource,
.reset_port = s3c2412_serial_resetport,
};
/* device management */
static int s3c2412_serial_probe(struct platform_device *dev)
{
dbg("s3c2440_serial_probe: dev=%p\n", dev);
return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
}
static struct platform_driver s3c2412_serial_drv = {
.probe = s3c2412_serial_probe,
.remove = s3c24xx_serial_remove,
.suspend = s3c24xx_serial_suspend,
.resume = s3c24xx_serial_resume,
.driver = {
.name = "s3c2412-uart",
.owner = THIS_MODULE,
},
};
static inline int s3c2412_serial_init(void)
{
return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf);
}
static inline void s3c2412_serial_exit(void)
{
platform_driver_unregister(&s3c2412_serial_drv);
}
#define s3c2412_uart_inf_at &s3c2412_uart_inf
#else
static inline int s3c2412_serial_init(void)
{
return 0;
}
static inline void s3c2412_serial_exit(void)
{
}
#define s3c2412_uart_inf_at NULL
#endif /* CONFIG_CPU_S3C2440 */
/* module initialisation code */
static int __init s3c24xx_serial_modinit(void)
......@@ -1542,6 +1679,7 @@ static int __init s3c24xx_serial_modinit(void)
s3c2400_serial_init();
s3c2410_serial_init();
s3c2412_serial_init();
s3c2440_serial_init();
return 0;
......@@ -1551,6 +1689,7 @@ static void __exit s3c24xx_serial_modexit(void)
{
s3c2400_serial_exit();
s3c2410_serial_exit();
s3c2412_serial_exit();
s3c2440_serial_exit();
uart_unregister_driver(&s3c24xx_uart_drv);
......@@ -1773,6 +1912,8 @@ static int s3c24xx_serial_initconsole(void)
info = s3c2410_uart_inf_at;
} else if (strcmp(dev->name, "s3c2440-uart") == 0) {
info = s3c2440_uart_inf_at;
} else if (strcmp(dev->name, "s3c2412-uart") == 0) {
info = s3c2412_uart_inf_at;
} else {
printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name);
return 0;
......@@ -1796,4 +1937,4 @@ console_initcall(s3c24xx_serial_initconsole);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("Samsung S3C2410/S3C2440 Serial port driver");
MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver");
......@@ -82,6 +82,12 @@
#define S3C2440_UCON2_DIVMASK (7 << 12)
#define S3C2440_UCON_DIVSHIFT (12)
#define S3C2412_UCON_CLKMASK (3<<10)
#define S3C2412_UCON_UCLK (1<<10)
#define S3C2412_UCON_USYSCLK (3<<10)
#define S3C2412_UCON_PCLK (0<<10)
#define S3C2412_UCON_PCLK2 (2<<10)
#define S3C2410_UCON_UCLK (1<<10)
#define S3C2410_UCON_SBREAK (1<<4)
......@@ -124,6 +130,15 @@
#define S3C2410_UMCOM_AFC (1<<4)
#define S3C2410_UMCOM_RTS_LOW (1<<0)
#define S3C2412_UMCON_AFC_63 (0<<5)
#define S3C2412_UMCON_AFC_56 (1<<5)
#define S3C2412_UMCON_AFC_48 (2<<5)
#define S3C2412_UMCON_AFC_40 (3<<5)
#define S3C2412_UMCON_AFC_32 (4<<5)
#define S3C2412_UMCON_AFC_24 (5<<5)
#define S3C2412_UMCON_AFC_16 (6<<5)
#define S3C2412_UMCON_AFC_8 (7<<5)
#define S3C2410_UFSTAT_TXFULL (1<<9)
#define S3C2410_UFSTAT_RXFULL (1<<8)
#define S3C2410_UFSTAT_TXMASK (15<<4)
......
......@@ -130,6 +130,9 @@
/* SUN4V Hypervisor Console */
#define PORT_SUNHV 72
#define PORT_S3C2412 73
#ifdef __KERNEL__
#include <linux/compiler.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment