Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -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
+142 −1
Original line number Diff line number Diff line
@@ -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");
+15 −0
Original line number Diff line number Diff line
@@ -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)
+3 −0
Original line number Diff line number Diff line
@@ -130,6 +130,9 @@
/* SUN4V Hypervisor Console */
#define PORT_SUNHV	72

#define PORT_S3C2412	73


#ifdef __KERNEL__

#include <linux/compiler.h>