diff options
Diffstat (limited to 'drivers')
| -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"); |
