diff options
author | Ben Dooks <ben-linux@fluff.org> | 2006-06-24 16:21:32 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-06-24 16:21:32 -0400 |
commit | 73e55cb3b3549d0174d1dadb755200938232e8d0 (patch) | |
tree | 041dc51100fae9a8da403a69a7d966f99c578bc9 /drivers/serial | |
parent | 736855f0c748dacb624070b8d6ffffe4532cf4dc (diff) |
[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: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/Kconfig | 9 | ||||
-rw-r--r-- | drivers/serial/s3c2410.c | 143 |
2 files changed, 148 insertions, 4 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index bef4a9622ed7..5b48ac22c9c5 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
@@ -354,21 +354,24 @@ config SERIAL_CLPS711X_CONSOLE | |||
354 | kernel at boot time.) | 354 | kernel at boot time.) |
355 | 355 | ||
356 | config SERIAL_S3C2410 | 356 | config SERIAL_S3C2410 |
357 | tristate "Samsung S3C2410 Serial port support" | 357 | tristate "Samsung S3C2410/S3C2440/S3C2442/S3C2412 Serial port support" |
358 | depends on ARM && ARCH_S3C2410 | 358 | depends on ARM && ARCH_S3C2410 |
359 | select SERIAL_CORE | 359 | select SERIAL_CORE |
360 | help | 360 | help |
361 | Support for the on-chip UARTs on the Samsung S3C2410X CPU, | 361 | Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, |
362 | providing /dev/ttySAC0, 1 and 2 (note, some machines may not | 362 | providing /dev/ttySAC0, 1 and 2 (note, some machines may not |
363 | provide all of these ports, depending on how the serial port | 363 | provide all of these ports, depending on how the serial port |
364 | pins are configured. | 364 | pins are configured. |
365 | 365 | ||
366 | Currently this driver supports the UARTS on the S3C2410, S3C2440, | ||
367 | S3C2442, S3C2412 and S3C2413 CPUs. | ||
368 | |||
366 | config SERIAL_S3C2410_CONSOLE | 369 | config SERIAL_S3C2410_CONSOLE |
367 | bool "Support for console on S3C2410 serial port" | 370 | bool "Support for console on S3C2410 serial port" |
368 | depends on SERIAL_S3C2410=y | 371 | depends on SERIAL_S3C2410=y |
369 | select SERIAL_CORE_CONSOLE | 372 | select SERIAL_CORE_CONSOLE |
370 | help | 373 | help |
371 | Allow selection of the S3C2410 on-board serial ports for use as | 374 | Allow selection of the S3C24XX on-board serial ports for use as |
372 | an virtual console. | 375 | an virtual console. |
373 | 376 | ||
374 | Even if you say Y here, the currently visible virtual console | 377 | Even if you say Y here, the currently visible virtual console |
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 53c2465bad2d..837b6da520b3 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c | |||
@@ -872,6 +872,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port) | |||
872 | return "S3C2410"; | 872 | return "S3C2410"; |
873 | case PORT_S3C2440: | 873 | case PORT_S3C2440: |
874 | return "S3C2440"; | 874 | return "S3C2440"; |
875 | case PORT_S3C2412: | ||
876 | return "S3C2412"; | ||
875 | default: | 877 | default: |
876 | return NULL; | 878 | return NULL; |
877 | } | 879 | } |
@@ -1528,6 +1530,141 @@ static inline void s3c2440_serial_exit(void) | |||
1528 | #define s3c2440_uart_inf_at NULL | 1530 | #define s3c2440_uart_inf_at NULL |
1529 | #endif /* CONFIG_CPU_S3C2440 */ | 1531 | #endif /* CONFIG_CPU_S3C2440 */ |
1530 | 1532 | ||
1533 | #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) | ||
1534 | |||
1535 | static int s3c2412_serial_setsource(struct uart_port *port, | ||
1536 | struct s3c24xx_uart_clksrc *clk) | ||
1537 | { | ||
1538 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | ||
1539 | |||
1540 | ucon &= ~S3C2412_UCON_CLKMASK; | ||
1541 | |||
1542 | if (strcmp(clk->name, "uclk") == 0) | ||
1543 | ucon |= S3C2440_UCON_UCLK; | ||
1544 | else if (strcmp(clk->name, "pclk") == 0) | ||
1545 | ucon |= S3C2440_UCON_PCLK; | ||
1546 | else if (strcmp(clk->name, "usysclk") == 0) | ||
1547 | ucon |= S3C2412_UCON_USYSCLK; | ||
1548 | else { | ||
1549 | printk(KERN_ERR "unknown clock source %s\n", clk->name); | ||
1550 | return -EINVAL; | ||
1551 | } | ||
1552 | |||
1553 | wr_regl(port, S3C2410_UCON, ucon); | ||
1554 | return 0; | ||
1555 | } | ||
1556 | |||
1557 | |||
1558 | static int s3c2412_serial_getsource(struct uart_port *port, | ||
1559 | struct s3c24xx_uart_clksrc *clk) | ||
1560 | { | ||
1561 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | ||
1562 | |||
1563 | switch (ucon & S3C2412_UCON_CLKMASK) { | ||
1564 | case S3C2412_UCON_UCLK: | ||
1565 | clk->divisor = 1; | ||
1566 | clk->name = "uclk"; | ||
1567 | break; | ||
1568 | |||
1569 | case S3C2412_UCON_PCLK: | ||
1570 | case S3C2412_UCON_PCLK2: | ||
1571 | clk->divisor = 1; | ||
1572 | clk->name = "pclk"; | ||
1573 | break; | ||
1574 | |||
1575 | case S3C2412_UCON_USYSCLK: | ||
1576 | clk->divisor = 1; | ||
1577 | clk->name = "usysclk"; | ||
1578 | break; | ||
1579 | } | ||
1580 | |||
1581 | return 0; | ||
1582 | } | ||
1583 | |||
1584 | static int s3c2412_serial_resetport(struct uart_port *port, | ||
1585 | struct s3c2410_uartcfg *cfg) | ||
1586 | { | ||
1587 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | ||
1588 | |||
1589 | dbg("%s: port=%p (%08lx), cfg=%p\n", | ||
1590 | __FUNCTION__, port, port->mapbase, cfg); | ||
1591 | |||
1592 | /* ensure we don't change the clock settings... */ | ||
1593 | |||
1594 | ucon &= S3C2412_UCON_CLKMASK; | ||
1595 | |||
1596 | wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); | ||
1597 | wr_regl(port, S3C2410_ULCON, cfg->ulcon); | ||
1598 | |||
1599 | /* reset both fifos */ | ||
1600 | |||
1601 | wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); | ||
1602 | wr_regl(port, S3C2410_UFCON, cfg->ufcon); | ||
1603 | |||
1604 | return 0; | ||
1605 | } | ||
1606 | |||
1607 | static struct s3c24xx_uart_info s3c2412_uart_inf = { | ||
1608 | .name = "Samsung S3C2412 UART", | ||
1609 | .type = PORT_S3C2412, | ||
1610 | .fifosize = 64, | ||
1611 | .rx_fifomask = S3C2440_UFSTAT_RXMASK, | ||
1612 | .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, | ||
1613 | .rx_fifofull = S3C2440_UFSTAT_RXFULL, | ||
1614 | .tx_fifofull = S3C2440_UFSTAT_TXFULL, | ||
1615 | .tx_fifomask = S3C2440_UFSTAT_TXMASK, | ||
1616 | .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, | ||
1617 | .get_clksrc = s3c2412_serial_getsource, | ||
1618 | .set_clksrc = s3c2412_serial_setsource, | ||
1619 | .reset_port = s3c2412_serial_resetport, | ||
1620 | }; | ||
1621 | |||
1622 | /* device management */ | ||
1623 | |||
1624 | static int s3c2412_serial_probe(struct platform_device *dev) | ||
1625 | { | ||
1626 | dbg("s3c2440_serial_probe: dev=%p\n", dev); | ||
1627 | return s3c24xx_serial_probe(dev, &s3c2440_uart_inf); | ||
1628 | } | ||
1629 | |||
1630 | static struct platform_driver s3c2412_serial_drv = { | ||
1631 | .probe = s3c2412_serial_probe, | ||
1632 | .remove = s3c24xx_serial_remove, | ||
1633 | .suspend = s3c24xx_serial_suspend, | ||
1634 | .resume = s3c24xx_serial_resume, | ||
1635 | .driver = { | ||
1636 | .name = "s3c2412-uart", | ||
1637 | .owner = THIS_MODULE, | ||
1638 | }, | ||
1639 | }; | ||
1640 | |||
1641 | |||
1642 | static inline int s3c2412_serial_init(void) | ||
1643 | { | ||
1644 | return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf); | ||
1645 | } | ||
1646 | |||
1647 | static inline void s3c2412_serial_exit(void) | ||
1648 | { | ||
1649 | platform_driver_unregister(&s3c2412_serial_drv); | ||
1650 | } | ||
1651 | |||
1652 | #define s3c2412_uart_inf_at &s3c2412_uart_inf | ||
1653 | #else | ||
1654 | |||
1655 | static inline int s3c2412_serial_init(void) | ||
1656 | { | ||
1657 | return 0; | ||
1658 | } | ||
1659 | |||
1660 | static inline void s3c2412_serial_exit(void) | ||
1661 | { | ||
1662 | } | ||
1663 | |||
1664 | #define s3c2412_uart_inf_at NULL | ||
1665 | #endif /* CONFIG_CPU_S3C2440 */ | ||
1666 | |||
1667 | |||
1531 | /* module initialisation code */ | 1668 | /* module initialisation code */ |
1532 | 1669 | ||
1533 | static int __init s3c24xx_serial_modinit(void) | 1670 | static int __init s3c24xx_serial_modinit(void) |
@@ -1542,6 +1679,7 @@ static int __init s3c24xx_serial_modinit(void) | |||
1542 | 1679 | ||
1543 | s3c2400_serial_init(); | 1680 | s3c2400_serial_init(); |
1544 | s3c2410_serial_init(); | 1681 | s3c2410_serial_init(); |
1682 | s3c2412_serial_init(); | ||
1545 | s3c2440_serial_init(); | 1683 | s3c2440_serial_init(); |
1546 | 1684 | ||
1547 | return 0; | 1685 | return 0; |
@@ -1551,6 +1689,7 @@ static void __exit s3c24xx_serial_modexit(void) | |||
1551 | { | 1689 | { |
1552 | s3c2400_serial_exit(); | 1690 | s3c2400_serial_exit(); |
1553 | s3c2410_serial_exit(); | 1691 | s3c2410_serial_exit(); |
1692 | s3c2412_serial_exit(); | ||
1554 | s3c2440_serial_exit(); | 1693 | s3c2440_serial_exit(); |
1555 | 1694 | ||
1556 | uart_unregister_driver(&s3c24xx_uart_drv); | 1695 | uart_unregister_driver(&s3c24xx_uart_drv); |
@@ -1773,6 +1912,8 @@ static int s3c24xx_serial_initconsole(void) | |||
1773 | info = s3c2410_uart_inf_at; | 1912 | info = s3c2410_uart_inf_at; |
1774 | } else if (strcmp(dev->name, "s3c2440-uart") == 0) { | 1913 | } else if (strcmp(dev->name, "s3c2440-uart") == 0) { |
1775 | info = s3c2440_uart_inf_at; | 1914 | info = s3c2440_uart_inf_at; |
1915 | } else if (strcmp(dev->name, "s3c2412-uart") == 0) { | ||
1916 | info = s3c2412_uart_inf_at; | ||
1776 | } else { | 1917 | } else { |
1777 | printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name); | 1918 | printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name); |
1778 | return 0; | 1919 | return 0; |
@@ -1796,4 +1937,4 @@ console_initcall(s3c24xx_serial_initconsole); | |||
1796 | 1937 | ||
1797 | MODULE_LICENSE("GPL"); | 1938 | MODULE_LICENSE("GPL"); |
1798 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | 1939 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); |
1799 | MODULE_DESCRIPTION("Samsung S3C2410/S3C2440 Serial port driver"); | 1940 | MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver"); |