aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/Kconfig44
-rw-r--r--drivers/tty/serial/Makefile5
-rw-r--r--drivers/tty/serial/s3c2410.c115
-rw-r--r--drivers/tty/serial/s3c2412.c149
-rw-r--r--drivers/tty/serial/s3c2440.c178
-rw-r--r--drivers/tty/serial/s3c6400.c149
-rw-r--r--drivers/tty/serial/s5pv210.c158
-rw-r--r--drivers/tty/serial/samsung.c639
-rw-r--r--drivers/tty/serial/samsung.h32
9 files changed, 398 insertions, 1071 deletions
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 113fccf8251..f32a2ea7010 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -462,7 +462,7 @@ config SERIAL_SAMSUNG
462config SERIAL_SAMSUNG_UARTS_4 462config SERIAL_SAMSUNG_UARTS_4
463 bool 463 bool
464 depends on ARM && PLAT_SAMSUNG 464 depends on ARM && PLAT_SAMSUNG
465 default y if CPU_S3C2443 465 default y if !(CPU_S3C2410 || SERIAL_S3C2412 || CPU_S3C2440 || CPU_S3C2442)
466 help 466 help
467 Internal node for the common case of 4 Samsung compatible UARTs 467 Internal node for the common case of 4 Samsung compatible UARTs
468 468
@@ -470,7 +470,7 @@ config SERIAL_SAMSUNG_UARTS
470 int 470 int
471 depends on ARM && PLAT_SAMSUNG 471 depends on ARM && PLAT_SAMSUNG
472 default 6 if ARCH_S5P6450 472 default 6 if ARCH_S5P6450
473 default 4 if SERIAL_SAMSUNG_UARTS_4 473 default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416
474 default 3 474 default 3
475 help 475 help
476 Select the number of available UART ports for the Samsung S3C 476 Select the number of available UART ports for the Samsung S3C
@@ -500,46 +500,6 @@ config SERIAL_SAMSUNG_CONSOLE
500 your boot loader about how to pass options to the kernel at 500 your boot loader about how to pass options to the kernel at
501 boot time.) 501 boot time.)
502 502
503config SERIAL_S3C2410
504 tristate "Samsung S3C2410 Serial port support"
505 depends on SERIAL_SAMSUNG && CPU_S3C2410
506 default y if CPU_S3C2410
507 help
508 Serial port support for the Samsung S3C2410 SoC
509
510config SERIAL_S3C2412
511 tristate "Samsung S3C2412/S3C2413 Serial port support"
512 depends on SERIAL_SAMSUNG && CPU_S3C2412
513 default y if CPU_S3C2412
514 help
515 Serial port support for the Samsung S3C2412 and S3C2413 SoC
516
517config SERIAL_S3C2440
518 tristate "Samsung S3C2440/S3C2442/S3C2416 Serial port support"
519 depends on SERIAL_SAMSUNG && (CPU_S3C2440 || CPU_S3C2442 || CPU_S3C2416)
520 default y if CPU_S3C2440
521 default y if CPU_S3C2442
522 select SERIAL_SAMSUNG_UARTS_4 if CPU_S3C2416
523 help
524 Serial port support for the Samsung S3C2440, S3C2416 and S3C2442 SoC
525
526config SERIAL_S3C6400
527 tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support"
528 depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100)
529 select SERIAL_SAMSUNG_UARTS_4
530 default y
531 help
532 Serial port support for the Samsung S3C6400, S3C6410, S5P6440, S5P6450
533 and S5PC100 SoCs
534
535config SERIAL_S5PV210
536 tristate "Samsung S5PV210 Serial port support"
537 depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_EXYNOS4210 || SOC_EXYNOS4212)
538 select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210 || SOC_EXYNOS4212)
539 default y
540 help
541 Serial port support for Samsung's S5P Family of SoC's
542
543config SERIAL_SIRFSOC 503config SERIAL_SIRFSOC
544 tristate "SiRF SoC Platform Serial port support" 504 tristate "SiRF SoC Platform Serial port support"
545 depends on ARM && ARCH_PRIMA2 505 depends on ARM && ARCH_PRIMA2
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 75eadb8d717..07e0494c683 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -40,11 +40,6 @@ obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
40obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o 40obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o
41obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o 41obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
42obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o 42obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
43obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
44obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
45obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
46obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
47obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o
48obj-$(CONFIG_SERIAL_MAX3100) += max3100.o 43obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
49obj-$(CONFIG_SERIAL_MAX3107) += max3107.o 44obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
50obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o 45obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o
diff --git a/drivers/tty/serial/s3c2410.c b/drivers/tty/serial/s3c2410.c
deleted file mode 100644
index b1d7e7c1849..00000000000
--- a/drivers/tty/serial/s3c2410.c
+++ /dev/null
@@ -1,115 +0,0 @@
1/*
2 * Driver for Samsung S3C2410 SoC onboard UARTs.
3 *
4 * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
5 * http://armlinux.simtec.co.uk/
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11
12#include <linux/module.h>
13#include <linux/ioport.h>
14#include <linux/io.h>
15#include <linux/platform_device.h>
16#include <linux/init.h>
17#include <linux/serial_core.h>
18#include <linux/serial.h>
19
20#include <asm/irq.h>
21#include <mach/hardware.h>
22
23#include <plat/regs-serial.h>
24#include <mach/regs-gpio.h>
25
26#include "samsung.h"
27
28static int s3c2410_serial_setsource(struct uart_port *port,
29 struct s3c24xx_uart_clksrc *clk)
30{
31 unsigned long ucon = rd_regl(port, S3C2410_UCON);
32
33 if (strcmp(clk->name, "uclk") == 0)
34 ucon |= S3C2410_UCON_UCLK;
35 else
36 ucon &= ~S3C2410_UCON_UCLK;
37
38 wr_regl(port, S3C2410_UCON, ucon);
39 return 0;
40}
41
42static int s3c2410_serial_getsource(struct uart_port *port,
43 struct s3c24xx_uart_clksrc *clk)
44{
45 unsigned long ucon = rd_regl(port, S3C2410_UCON);
46
47 clk->divisor = 1;
48 clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
49
50 return 0;
51}
52
53static int s3c2410_serial_resetport(struct uart_port *port,
54 struct s3c2410_uartcfg *cfg)
55{
56 dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",
57 port, port->mapbase, cfg);
58
59 wr_regl(port, S3C2410_UCON, cfg->ucon);
60 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
61
62 /* reset both fifos */
63
64 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
65 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
66
67 return 0;
68}
69
70static struct s3c24xx_uart_info s3c2410_uart_inf = {
71 .name = "Samsung S3C2410 UART",
72 .type = PORT_S3C2410,
73 .fifosize = 16,
74 .rx_fifomask = S3C2410_UFSTAT_RXMASK,
75 .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT,
76 .rx_fifofull = S3C2410_UFSTAT_RXFULL,
77 .tx_fifofull = S3C2410_UFSTAT_TXFULL,
78 .tx_fifomask = S3C2410_UFSTAT_TXMASK,
79 .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT,
80 .get_clksrc = s3c2410_serial_getsource,
81 .set_clksrc = s3c2410_serial_setsource,
82 .reset_port = s3c2410_serial_resetport,
83};
84
85static int s3c2410_serial_probe(struct platform_device *dev)
86{
87 return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
88}
89
90static struct platform_driver s3c2410_serial_driver = {
91 .probe = s3c2410_serial_probe,
92 .remove = __devexit_p(s3c24xx_serial_remove),
93 .driver = {
94 .name = "s3c2410-uart",
95 .owner = THIS_MODULE,
96 },
97};
98
99static int __init s3c2410_serial_init(void)
100{
101 return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
102}
103
104static void __exit s3c2410_serial_exit(void)
105{
106 platform_driver_unregister(&s3c2410_serial_driver);
107}
108
109module_init(s3c2410_serial_init);
110module_exit(s3c2410_serial_exit);
111
112MODULE_LICENSE("GPL v2");
113MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
114MODULE_DESCRIPTION("Samsung S3C2410 SoC Serial port driver");
115MODULE_ALIAS("platform:s3c2410-uart");
diff --git a/drivers/tty/serial/s3c2412.c b/drivers/tty/serial/s3c2412.c
deleted file mode 100644
index 2234bf9ced4..00000000000
--- a/drivers/tty/serial/s3c2412.c
+++ /dev/null
@@ -1,149 +0,0 @@
1/*
2 * Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs.
3 *
4 * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
5 * http://armlinux.simtec.co.uk/
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11
12#include <linux/module.h>
13#include <linux/ioport.h>
14#include <linux/io.h>
15#include <linux/platform_device.h>
16#include <linux/init.h>
17#include <linux/serial_core.h>
18#include <linux/serial.h>
19
20#include <asm/irq.h>
21#include <mach/hardware.h>
22
23#include <plat/regs-serial.h>
24#include <mach/regs-gpio.h>
25
26#include "samsung.h"
27
28static int s3c2412_serial_setsource(struct uart_port *port,
29 struct s3c24xx_uart_clksrc *clk)
30{
31 unsigned long ucon = rd_regl(port, S3C2410_UCON);
32
33 ucon &= ~S3C2412_UCON_CLKMASK;
34
35 if (strcmp(clk->name, "uclk") == 0)
36 ucon |= S3C2440_UCON_UCLK;
37 else if (strcmp(clk->name, "pclk") == 0)
38 ucon |= S3C2440_UCON_PCLK;
39 else if (strcmp(clk->name, "usysclk") == 0)
40 ucon |= S3C2412_UCON_USYSCLK;
41 else {
42 printk(KERN_ERR "unknown clock source %s\n", clk->name);
43 return -EINVAL;
44 }
45
46 wr_regl(port, S3C2410_UCON, ucon);
47 return 0;
48}
49
50
51static int s3c2412_serial_getsource(struct uart_port *port,
52 struct s3c24xx_uart_clksrc *clk)
53{
54 unsigned long ucon = rd_regl(port, S3C2410_UCON);
55
56 switch (ucon & S3C2412_UCON_CLKMASK) {
57 case S3C2412_UCON_UCLK:
58 clk->divisor = 1;
59 clk->name = "uclk";
60 break;
61
62 case S3C2412_UCON_PCLK:
63 case S3C2412_UCON_PCLK2:
64 clk->divisor = 1;
65 clk->name = "pclk";
66 break;
67
68 case S3C2412_UCON_USYSCLK:
69 clk->divisor = 1;
70 clk->name = "usysclk";
71 break;
72 }
73
74 return 0;
75}
76
77static int s3c2412_serial_resetport(struct uart_port *port,
78 struct s3c2410_uartcfg *cfg)
79{
80 unsigned long ucon = rd_regl(port, S3C2410_UCON);
81
82 dbg("%s: port=%p (%08lx), cfg=%p\n",
83 __func__, port, port->mapbase, cfg);
84
85 /* ensure we don't change the clock settings... */
86
87 ucon &= S3C2412_UCON_CLKMASK;
88
89 wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
90 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
91
92 /* reset both fifos */
93
94 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
95 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
96
97 return 0;
98}
99
100static struct s3c24xx_uart_info s3c2412_uart_inf = {
101 .name = "Samsung S3C2412 UART",
102 .type = PORT_S3C2412,
103 .fifosize = 64,
104 .has_divslot = 1,
105 .rx_fifomask = S3C2440_UFSTAT_RXMASK,
106 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
107 .rx_fifofull = S3C2440_UFSTAT_RXFULL,
108 .tx_fifofull = S3C2440_UFSTAT_TXFULL,
109 .tx_fifomask = S3C2440_UFSTAT_TXMASK,
110 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
111 .get_clksrc = s3c2412_serial_getsource,
112 .set_clksrc = s3c2412_serial_setsource,
113 .reset_port = s3c2412_serial_resetport,
114};
115
116/* device management */
117
118static int s3c2412_serial_probe(struct platform_device *dev)
119{
120 dbg("s3c2440_serial_probe: dev=%p\n", dev);
121 return s3c24xx_serial_probe(dev, &s3c2412_uart_inf);
122}
123
124static struct platform_driver s3c2412_serial_driver = {
125 .probe = s3c2412_serial_probe,
126 .remove = __devexit_p(s3c24xx_serial_remove),
127 .driver = {
128 .name = "s3c2412-uart",
129 .owner = THIS_MODULE,
130 },
131};
132
133static inline int s3c2412_serial_init(void)
134{
135 return s3c24xx_serial_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
136}
137
138static inline void s3c2412_serial_exit(void)
139{
140 platform_driver_unregister(&s3c2412_serial_driver);
141}
142
143module_init(s3c2412_serial_init);
144module_exit(s3c2412_serial_exit);
145
146MODULE_DESCRIPTION("Samsung S3C2412,S3C2413 SoC Serial port driver");
147MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
148MODULE_LICENSE("GPL v2");
149MODULE_ALIAS("platform:s3c2412-uart");
diff --git a/drivers/tty/serial/s3c2440.c b/drivers/tty/serial/s3c2440.c
deleted file mode 100644
index 1d0c324b813..00000000000
--- a/drivers/tty/serial/s3c2440.c
+++ /dev/null
@@ -1,178 +0,0 @@
1/*
2 * Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs.
3 *
4 * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
5 * http://armlinux.simtec.co.uk/
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11
12#include <linux/module.h>
13#include <linux/ioport.h>
14#include <linux/io.h>
15#include <linux/platform_device.h>
16#include <linux/init.h>
17#include <linux/serial_core.h>
18#include <linux/serial.h>
19
20#include <asm/irq.h>
21#include <mach/hardware.h>
22
23#include <plat/regs-serial.h>
24#include <mach/regs-gpio.h>
25
26#include "samsung.h"
27
28
29static int s3c2440_serial_setsource(struct uart_port *port,
30 struct s3c24xx_uart_clksrc *clk)
31{
32 unsigned long ucon = rd_regl(port, S3C2410_UCON);
33
34 /* todo - proper fclk<>nonfclk switch. */
35
36 ucon &= ~S3C2440_UCON_CLKMASK;
37
38 if (strcmp(clk->name, "uclk") == 0)
39 ucon |= S3C2440_UCON_UCLK;
40 else if (strcmp(clk->name, "pclk") == 0)
41 ucon |= S3C2440_UCON_PCLK;
42 else if (strcmp(clk->name, "fclk") == 0)
43 ucon |= S3C2440_UCON_FCLK;
44 else {
45 printk(KERN_ERR "unknown clock source %s\n", clk->name);
46 return -EINVAL;
47 }
48
49 wr_regl(port, S3C2410_UCON, ucon);
50 return 0;
51}
52
53
54static int s3c2440_serial_getsource(struct uart_port *port,
55 struct s3c24xx_uart_clksrc *clk)
56{
57 unsigned long ucon = rd_regl(port, S3C2410_UCON);
58 unsigned long ucon0, ucon1, ucon2;
59
60 switch (ucon & S3C2440_UCON_CLKMASK) {
61 case S3C2440_UCON_UCLK:
62 clk->divisor = 1;
63 clk->name = "uclk";
64 break;
65
66 case S3C2440_UCON_PCLK:
67 case S3C2440_UCON_PCLK2:
68 clk->divisor = 1;
69 clk->name = "pclk";
70 break;
71
72 case S3C2440_UCON_FCLK:
73 /* the fun of calculating the uart divisors on
74 * the s3c2440 */
75
76 ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
77 ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
78 ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
79
80 printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
81
82 ucon0 &= S3C2440_UCON0_DIVMASK;
83 ucon1 &= S3C2440_UCON1_DIVMASK;
84 ucon2 &= S3C2440_UCON2_DIVMASK;
85
86 if (ucon0 != 0) {
87 clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
88 clk->divisor += 6;
89 } else if (ucon1 != 0) {
90 clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
91 clk->divisor += 21;
92 } else if (ucon2 != 0) {
93 clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
94 clk->divisor += 36;
95 } else {
96 /* manual calims 44, seems to be 9 */
97 clk->divisor = 9;
98 }
99
100 clk->name = "fclk";
101 break;
102 }
103
104 return 0;
105}
106
107static int s3c2440_serial_resetport(struct uart_port *port,
108 struct s3c2410_uartcfg *cfg)
109{
110 unsigned long ucon = rd_regl(port, S3C2410_UCON);
111
112 dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n",
113 port, port->mapbase, cfg);
114
115 /* ensure we don't change the clock settings... */
116
117 ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));
118
119 wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
120 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
121
122 /* reset both fifos */
123
124 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
125 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
126
127 return 0;
128}
129
130static struct s3c24xx_uart_info s3c2440_uart_inf = {
131 .name = "Samsung S3C2440 UART",
132 .type = PORT_S3C2440,
133 .fifosize = 64,
134 .rx_fifomask = S3C2440_UFSTAT_RXMASK,
135 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
136 .rx_fifofull = S3C2440_UFSTAT_RXFULL,
137 .tx_fifofull = S3C2440_UFSTAT_TXFULL,
138 .tx_fifomask = S3C2440_UFSTAT_TXMASK,
139 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
140 .get_clksrc = s3c2440_serial_getsource,
141 .set_clksrc = s3c2440_serial_setsource,
142 .reset_port = s3c2440_serial_resetport,
143};
144
145/* device management */
146
147static int s3c2440_serial_probe(struct platform_device *dev)
148{
149 dbg("s3c2440_serial_probe: dev=%p\n", dev);
150 return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
151}
152
153static struct platform_driver s3c2440_serial_driver = {
154 .probe = s3c2440_serial_probe,
155 .remove = __devexit_p(s3c24xx_serial_remove),
156 .driver = {
157 .name = "s3c2440-uart",
158 .owner = THIS_MODULE,
159 },
160};
161
162static int __init s3c2440_serial_init(void)
163{
164 return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
165}
166
167static void __exit s3c2440_serial_exit(void)
168{
169 platform_driver_unregister(&s3c2440_serial_driver);
170}
171
172module_init(s3c2440_serial_init);
173module_exit(s3c2440_serial_exit);
174
175MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver");
176MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
177MODULE_LICENSE("GPL v2");
178MODULE_ALIAS("platform:s3c2440-uart");
diff --git a/drivers/tty/serial/s3c6400.c b/drivers/tty/serial/s3c6400.c
deleted file mode 100644
index e2f6913d84d..00000000000
--- a/drivers/tty/serial/s3c6400.c
+++ /dev/null
@@ -1,149 +0,0 @@
1/*
2 * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs.
3 *
4 * Copyright 2008 Openmoko, Inc.
5 * Copyright 2008 Simtec Electronics
6 * Ben Dooks <ben@simtec.co.uk>
7 * http://armlinux.simtec.co.uk/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <linux/module.h>
15#include <linux/ioport.h>
16#include <linux/io.h>
17#include <linux/platform_device.h>
18#include <linux/init.h>
19#include <linux/serial_core.h>
20#include <linux/serial.h>
21
22#include <asm/irq.h>
23#include <mach/hardware.h>
24
25#include <plat/regs-serial.h>
26
27#include "samsung.h"
28
29static int s3c6400_serial_setsource(struct uart_port *port,
30 struct s3c24xx_uart_clksrc *clk)
31{
32 unsigned long ucon = rd_regl(port, S3C2410_UCON);
33
34 if (strcmp(clk->name, "uclk0") == 0) {
35 ucon &= ~S3C6400_UCON_CLKMASK;
36 ucon |= S3C6400_UCON_UCLK0;
37 } else if (strcmp(clk->name, "uclk1") == 0)
38 ucon |= S3C6400_UCON_UCLK1;
39 else if (strcmp(clk->name, "pclk") == 0) {
40 /* See notes about transitioning from UCLK to PCLK */
41 ucon &= ~S3C6400_UCON_UCLK0;
42 } else {
43 printk(KERN_ERR "unknown clock source %s\n", clk->name);
44 return -EINVAL;
45 }
46
47 wr_regl(port, S3C2410_UCON, ucon);
48 return 0;
49}
50
51
52static int s3c6400_serial_getsource(struct uart_port *port,
53 struct s3c24xx_uart_clksrc *clk)
54{
55 u32 ucon = rd_regl(port, S3C2410_UCON);
56
57 clk->divisor = 1;
58
59 switch (ucon & S3C6400_UCON_CLKMASK) {
60 case S3C6400_UCON_UCLK0:
61 clk->name = "uclk0";
62 break;
63
64 case S3C6400_UCON_UCLK1:
65 clk->name = "uclk1";
66 break;
67
68 case S3C6400_UCON_PCLK:
69 case S3C6400_UCON_PCLK2:
70 clk->name = "pclk";
71 break;
72 }
73
74 return 0;
75}
76
77static int s3c6400_serial_resetport(struct uart_port *port,
78 struct s3c2410_uartcfg *cfg)
79{
80 unsigned long ucon = rd_regl(port, S3C2410_UCON);
81
82 dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n",
83 port, port->mapbase, cfg);
84
85 /* ensure we don't change the clock settings... */
86
87 ucon &= S3C6400_UCON_CLKMASK;
88
89 wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
90 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
91
92 /* reset both fifos */
93
94 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
95 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
96
97 return 0;
98}
99
100static struct s3c24xx_uart_info s3c6400_uart_inf = {
101 .name = "Samsung S3C6400 UART",
102 .type = PORT_S3C6400,
103 .fifosize = 64,
104 .has_divslot = 1,
105 .rx_fifomask = S3C2440_UFSTAT_RXMASK,
106 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
107 .rx_fifofull = S3C2440_UFSTAT_RXFULL,
108 .tx_fifofull = S3C2440_UFSTAT_TXFULL,
109 .tx_fifomask = S3C2440_UFSTAT_TXMASK,
110 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
111 .get_clksrc = s3c6400_serial_getsource,
112 .set_clksrc = s3c6400_serial_setsource,
113 .reset_port = s3c6400_serial_resetport,
114};
115
116/* device management */
117
118static int s3c6400_serial_probe(struct platform_device *dev)
119{
120 dbg("s3c6400_serial_probe: dev=%p\n", dev);
121 return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);
122}
123
124static struct platform_driver s3c6400_serial_driver = {
125 .probe = s3c6400_serial_probe,
126 .remove = __devexit_p(s3c24xx_serial_remove),
127 .driver = {
128 .name = "s3c6400-uart",
129 .owner = THIS_MODULE,
130 },
131};
132
133static int __init s3c6400_serial_init(void)
134{
135 return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
136}
137
138static void __exit s3c6400_serial_exit(void)
139{
140 platform_driver_unregister(&s3c6400_serial_driver);
141}
142
143module_init(s3c6400_serial_init);
144module_exit(s3c6400_serial_exit);
145
146MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver");
147MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
148MODULE_LICENSE("GPL v2");
149MODULE_ALIAS("platform:s3c6400-uart");
diff --git a/drivers/tty/serial/s5pv210.c b/drivers/tty/serial/s5pv210.c
deleted file mode 100644
index 8b0b888a1b7..00000000000
--- a/drivers/tty/serial/s5pv210.c
+++ /dev/null
@@ -1,158 +0,0 @@
1/*
2 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * Based on drivers/serial/s3c6400.c
6 *
7 * Driver for Samsung S5PV210 SoC UARTs.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <linux/module.h>
15#include <linux/ioport.h>
16#include <linux/io.h>
17#include <linux/platform_device.h>
18#include <linux/init.h>
19#include <linux/serial_core.h>
20#include <linux/serial.h>
21#include <linux/delay.h>
22
23#include <asm/irq.h>
24#include <mach/hardware.h>
25#include <plat/regs-serial.h>
26#include "samsung.h"
27
28static int s5pv210_serial_setsource(struct uart_port *port,
29 struct s3c24xx_uart_clksrc *clk)
30{
31 struct s3c2410_uartcfg *cfg = port->dev->platform_data;
32 unsigned long ucon = rd_regl(port, S3C2410_UCON);
33
34 if (cfg->flags & NO_NEED_CHECK_CLKSRC)
35 return 0;
36
37 if (strcmp(clk->name, "pclk") == 0)
38 ucon &= ~S5PV210_UCON_CLKMASK;
39 else if (strcmp(clk->name, "uclk1") == 0)
40 ucon |= S5PV210_UCON_CLKMASK;
41 else {
42 printk(KERN_ERR "unknown clock source %s\n", clk->name);
43 return -EINVAL;
44 }
45
46 wr_regl(port, S3C2410_UCON, ucon);
47 return 0;
48}
49
50
51static int s5pv210_serial_getsource(struct uart_port *port,
52 struct s3c24xx_uart_clksrc *clk)
53{
54 struct s3c2410_uartcfg *cfg = port->dev->platform_data;
55 u32 ucon = rd_regl(port, S3C2410_UCON);
56
57 clk->divisor = 1;
58
59 if (cfg->flags & NO_NEED_CHECK_CLKSRC)
60 return 0;
61
62 switch (ucon & S5PV210_UCON_CLKMASK) {
63 case S5PV210_UCON_PCLK:
64 clk->name = "pclk";
65 break;
66 case S5PV210_UCON_UCLK:
67 clk->name = "uclk1";
68 break;
69 }
70
71 return 0;
72}
73
74static int s5pv210_serial_resetport(struct uart_port *port,
75 struct s3c2410_uartcfg *cfg)
76{
77 unsigned long ucon = rd_regl(port, S3C2410_UCON);
78
79 ucon &= S5PV210_UCON_CLKMASK;
80 wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
81 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
82
83 /* reset both fifos */
84 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
85 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
86
87 /* It is need to delay When reset FIFO register */
88 udelay(1);
89
90 return 0;
91}
92
93#define S5PV210_UART_DEFAULT_INFO(fifo_size) \
94 .name = "Samsung S5PV210 UART0", \
95 .type = PORT_S3C6400, \
96 .fifosize = fifo_size, \
97 .has_divslot = 1, \
98 .rx_fifomask = S5PV210_UFSTAT_RXMASK, \
99 .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \
100 .rx_fifofull = S5PV210_UFSTAT_RXFULL, \
101 .tx_fifofull = S5PV210_UFSTAT_TXFULL, \
102 .tx_fifomask = S5PV210_UFSTAT_TXMASK, \
103 .tx_fifoshift = S5PV210_UFSTAT_TXSHIFT, \
104 .get_clksrc = s5pv210_serial_getsource, \
105 .set_clksrc = s5pv210_serial_setsource, \
106 .reset_port = s5pv210_serial_resetport
107
108static struct s3c24xx_uart_info s5p_port_fifo256 = {
109 S5PV210_UART_DEFAULT_INFO(256),
110};
111
112static struct s3c24xx_uart_info s5p_port_fifo64 = {
113 S5PV210_UART_DEFAULT_INFO(64),
114};
115
116static struct s3c24xx_uart_info s5p_port_fifo16 = {
117 S5PV210_UART_DEFAULT_INFO(16),
118};
119
120static struct s3c24xx_uart_info *s5p_uart_inf[] = {
121 [0] = &s5p_port_fifo256,
122 [1] = &s5p_port_fifo64,
123 [2] = &s5p_port_fifo16,
124 [3] = &s5p_port_fifo16,
125};
126
127/* device management */
128static int s5p_serial_probe(struct platform_device *pdev)
129{
130 return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
131}
132
133static struct platform_driver s5p_serial_driver = {
134 .probe = s5p_serial_probe,
135 .remove = __devexit_p(s3c24xx_serial_remove),
136 .driver = {
137 .name = "s5pv210-uart",
138 .owner = THIS_MODULE,
139 },
140};
141
142static int __init s5p_serial_init(void)
143{
144 return s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf);
145}
146
147static void __exit s5p_serial_exit(void)
148{
149 platform_driver_unregister(&s5p_serial_driver);
150}
151
152module_init(s5p_serial_init);
153module_exit(s5p_serial_exit);
154
155MODULE_LICENSE("GPL");
156MODULE_ALIAS("platform:s5pv210-uart");
157MODULE_DESCRIPTION("Samsung S5PV210 UART Driver support");
158MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index b31f1c3a2c4..f96f37b5fec 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -42,6 +42,7 @@
42#include <linux/delay.h> 42#include <linux/delay.h>
43#include <linux/clk.h> 43#include <linux/clk.h>
44#include <linux/cpufreq.h> 44#include <linux/cpufreq.h>
45#include <linux/of.h>
45 46
46#include <asm/irq.h> 47#include <asm/irq.h>
47 48
@@ -49,6 +50,7 @@
49#include <mach/map.h> 50#include <mach/map.h>
50 51
51#include <plat/regs-serial.h> 52#include <plat/regs-serial.h>
53#include <plat/clock.h>
52 54
53#include "samsung.h" 55#include "samsung.h"
54 56
@@ -190,10 +192,13 @@ static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *p
190 192
191static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port) 193static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
192{ 194{
195 struct s3c24xx_uart_port *ourport;
196
193 if (port->dev == NULL) 197 if (port->dev == NULL)
194 return NULL; 198 return NULL;
195 199
196 return (struct s3c2410_uartcfg *)port->dev->platform_data; 200 ourport = container_of(port, struct s3c24xx_uart_port, port);
201 return ourport->cfg;
197} 202}
198 203
199static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport, 204static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
@@ -202,7 +207,7 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
202 struct s3c24xx_uart_info *info = ourport->info; 207 struct s3c24xx_uart_info *info = ourport->info;
203 208
204 if (ufstat & info->rx_fifofull) 209 if (ufstat & info->rx_fifofull)
205 return info->fifosize; 210 return ourport->port.fifosize;
206 211
207 return (ufstat & info->rx_fifomask) >> info->rx_fifoshift; 212 return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
208} 213}
@@ -555,154 +560,98 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
555 * 560 *
556*/ 561*/
557 562
563#define MAX_CLK_NAME_LENGTH 15
558 564
559#define MAX_CLKS (8) 565static inline int s3c24xx_serial_getsource(struct uart_port *port)
560
561static struct s3c24xx_uart_clksrc tmp_clksrc = {
562 .name = "pclk",
563 .min_baud = 0,
564 .max_baud = 0,
565 .divisor = 1,
566};
567
568static inline int
569s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
570{ 566{
571 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); 567 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
568 unsigned int ucon;
572 569
573 return (info->get_clksrc)(port, c); 570 if (info->num_clks == 1)
574} 571 return 0;
575
576static inline int
577s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
578{
579 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
580 572
581 return (info->set_clksrc)(port, c); 573 ucon = rd_regl(port, S3C2410_UCON);
574 ucon &= info->clksel_mask;
575 return ucon >> info->clksel_shift;
582} 576}
583 577
584struct baud_calc { 578static void s3c24xx_serial_setsource(struct uart_port *port,
585 struct s3c24xx_uart_clksrc *clksrc; 579 unsigned int clk_sel)
586 unsigned int calc;
587 unsigned int divslot;
588 unsigned int quot;
589 struct clk *src;
590};
591
592static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
593 struct uart_port *port,
594 struct s3c24xx_uart_clksrc *clksrc,
595 unsigned int baud)
596{ 580{
597 struct s3c24xx_uart_port *ourport = to_ourport(port); 581 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
598 unsigned long rate; 582 unsigned int ucon;
599
600 calc->src = clk_get(port->dev, clksrc->name);
601 if (calc->src == NULL || IS_ERR(calc->src))
602 return 0;
603
604 rate = clk_get_rate(calc->src);
605 rate /= clksrc->divisor;
606 583
607 calc->clksrc = clksrc; 584 if (info->num_clks == 1)
585 return;
608 586
609 if (ourport->info->has_divslot) { 587 ucon = rd_regl(port, S3C2410_UCON);
610 unsigned long div = rate / baud; 588 if ((ucon & info->clksel_mask) >> info->clksel_shift == clk_sel)
611 589 return;
612 /* The UDIVSLOT register on the newer UARTs allows us to
613 * get a divisor adjustment of 1/16th on the baud clock.
614 *
615 * We don't keep the UDIVSLOT value (the 16ths we calculated
616 * by not multiplying the baud by 16) as it is easy enough
617 * to recalculate.
618 */
619
620 calc->quot = div / 16;
621 calc->calc = rate / div;
622 } else {
623 calc->quot = (rate + (8 * baud)) / (16 * baud);
624 calc->calc = (rate / (calc->quot * 16));
625 }
626 590
627 calc->quot--; 591 ucon &= ~info->clksel_mask;
628 return 1; 592 ucon |= clk_sel << info->clksel_shift;
593 wr_regl(port, S3C2410_UCON, ucon);
629} 594}
630 595
631static unsigned int s3c24xx_serial_getclk(struct uart_port *port, 596static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
632 struct s3c24xx_uart_clksrc **clksrc, 597 unsigned int req_baud, struct clk **best_clk,
633 struct clk **clk, 598 unsigned int *clk_num)
634 unsigned int baud)
635{ 599{
636 struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); 600 struct s3c24xx_uart_info *info = ourport->info;
637 struct s3c24xx_uart_clksrc *clkp; 601 struct clk *clk;
638 struct baud_calc res[MAX_CLKS]; 602 unsigned long rate;
639 struct baud_calc *resptr, *best, *sptr; 603 unsigned int cnt, baud, quot, clk_sel, best_quot = 0;
640 int i; 604 char clkname[MAX_CLK_NAME_LENGTH];
641 605 int calc_deviation, deviation = (1 << 30) - 1;
642 clkp = cfg->clocks; 606
643 best = NULL; 607 *best_clk = NULL;
644 608 clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
645 if (cfg->clocks_size < 2) { 609 ourport->info->def_clk_sel;
646 if (cfg->clocks_size == 0) 610 for (cnt = 0; cnt < info->num_clks; cnt++) {
647 clkp = &tmp_clksrc; 611 if (!(clk_sel & (1 << cnt)))
648 612 continue;
649 /* check to see if we're sourcing fclk, and if so we're 613
650 * going to have to update the clock source 614 sprintf(clkname, "clk_uart_baud%d", cnt);
651 */ 615 clk = clk_get(ourport->port.dev, clkname);
652 616 if (IS_ERR_OR_NULL(clk))
653 if (strcmp(clkp->name, "fclk") == 0) { 617 continue;
654 struct s3c24xx_uart_clksrc src; 618
655 619 rate = clk_get_rate(clk);
656 s3c24xx_serial_getsource(port, &src); 620 if (!rate)
657 621 continue;
658 /* check that the port already using fclk, and if 622
659 * not, then re-select fclk 623 if (ourport->info->has_divslot) {
624 unsigned long div = rate / req_baud;
625
626 /* The UDIVSLOT register on the newer UARTs allows us to
627 * get a divisor adjustment of 1/16th on the baud clock.
628 *
629 * We don't keep the UDIVSLOT value (the 16ths we
630 * calculated by not multiplying the baud by 16) as it
631 * is easy enough to recalculate.
660 */ 632 */
661 633
662 if (strcmp(src.name, clkp->name) == 0) { 634 quot = div / 16;
663 s3c24xx_serial_setsource(port, clkp); 635 baud = rate / div;
664 s3c24xx_serial_getsource(port, &src); 636 } else {
665 } 637 quot = (rate + (8 * req_baud)) / (16 * req_baud);
666 638 baud = rate / (quot * 16);
667 clkp->divisor = src.divisor;
668 }
669
670 s3c24xx_serial_calcbaud(res, port, clkp, baud);
671 best = res;
672 resptr = best + 1;
673 } else {
674 resptr = res;
675
676 for (i = 0; i < cfg->clocks_size; i++, clkp++) {
677 if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
678 resptr++;
679 } 639 }
680 } 640 quot--;
681
682 /* ok, we now need to select the best clock we found */
683
684 if (!best) {
685 unsigned int deviation = (1<<30)|((1<<30)-1);
686 int calc_deviation;
687 641
688 for (sptr = res; sptr < resptr; sptr++) { 642 calc_deviation = req_baud - baud;
689 calc_deviation = baud - sptr->calc; 643 if (calc_deviation < 0)
690 if (calc_deviation < 0) 644 calc_deviation = -calc_deviation;
691 calc_deviation = -calc_deviation;
692 645
693 if (calc_deviation < deviation) { 646 if (calc_deviation < deviation) {
694 best = sptr; 647 *best_clk = clk;
695 deviation = calc_deviation; 648 best_quot = quot;
696 } 649 *clk_num = cnt;
650 deviation = calc_deviation;
697 } 651 }
698 } 652 }
699 653
700 /* store results to pass back */ 654 return best_quot;
701
702 *clksrc = best->clksrc;
703 *clk = best->src;
704
705 return best->quot;
706} 655}
707 656
708/* udivslot_table[] 657/* udivslot_table[]
@@ -735,10 +684,9 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
735{ 684{
736 struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); 685 struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
737 struct s3c24xx_uart_port *ourport = to_ourport(port); 686 struct s3c24xx_uart_port *ourport = to_ourport(port);
738 struct s3c24xx_uart_clksrc *clksrc = NULL;
739 struct clk *clk = NULL; 687 struct clk *clk = NULL;
740 unsigned long flags; 688 unsigned long flags;
741 unsigned int baud, quot; 689 unsigned int baud, quot, clk_sel = 0;
742 unsigned int ulcon; 690 unsigned int ulcon;
743 unsigned int umcon; 691 unsigned int umcon;
744 unsigned int udivslot = 0; 692 unsigned int udivslot = 0;
@@ -754,17 +702,16 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
754 */ 702 */
755 703
756 baud = uart_get_baud_rate(port, termios, old, 0, 115200*8); 704 baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
757 705 quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
758 if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) 706 if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
759 quot = port->custom_divisor; 707 quot = port->custom_divisor;
760 else 708 if (!clk)
761 quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud); 709 return;
762 710
763 /* check to see if we need to change clock source */ 711 /* check to see if we need to change clock source */
764 712
765 if (ourport->clksrc != clksrc || ourport->baudclk != clk) { 713 if (ourport->baudclk != clk) {
766 dbg("selecting clock %p\n", clk); 714 s3c24xx_serial_setsource(port, clk_sel);
767 s3c24xx_serial_setsource(port, clksrc);
768 715
769 if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { 716 if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
770 clk_disable(ourport->baudclk); 717 clk_disable(ourport->baudclk);
@@ -773,7 +720,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
773 720
774 clk_enable(clk); 721 clk_enable(clk);
775 722
776 ourport->clksrc = clksrc;
777 ourport->baudclk = clk; 723 ourport->baudclk = clk;
778 ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; 724 ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
779 } 725 }
@@ -1020,16 +966,29 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
1020 966
1021/* s3c24xx_serial_resetport 967/* s3c24xx_serial_resetport
1022 * 968 *
1023 * wrapper to call the specific reset for this port (reset the fifos 969 * reset the fifos and other the settings.
1024 * and the settings)
1025*/ 970*/
1026 971
1027static inline int s3c24xx_serial_resetport(struct uart_port *port, 972static void s3c24xx_serial_resetport(struct uart_port *port,
1028 struct s3c2410_uartcfg *cfg) 973 struct s3c2410_uartcfg *cfg)
1029{ 974{
1030 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); 975 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
976 unsigned long ucon = rd_regl(port, S3C2410_UCON);
977 unsigned int ucon_mask;
978
979 ucon_mask = info->clksel_mask;
980 if (info->type == PORT_S3C2440)
981 ucon_mask |= S3C2440_UCON0_DIVMASK;
1031 982
1032 return (info->reset_port)(port, cfg); 983 ucon &= ucon_mask;
984 wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
985
986 /* reset both fifos */
987 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
988 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
989
990 /* some delay is required after fifo reset */
991 udelay(1);
1033} 992}
1034 993
1035 994
@@ -1121,11 +1080,10 @@ static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *p
1121 */ 1080 */
1122 1081
1123static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, 1082static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
1124 struct s3c24xx_uart_info *info,
1125 struct platform_device *platdev) 1083 struct platform_device *platdev)
1126{ 1084{
1127 struct uart_port *port = &ourport->port; 1085 struct uart_port *port = &ourport->port;
1128 struct s3c2410_uartcfg *cfg; 1086 struct s3c2410_uartcfg *cfg = ourport->cfg;
1129 struct resource *res; 1087 struct resource *res;
1130 int ret; 1088 int ret;
1131 1089
@@ -1134,30 +1092,16 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
1134 if (platdev == NULL) 1092 if (platdev == NULL)
1135 return -ENODEV; 1093 return -ENODEV;
1136 1094
1137 cfg = s3c24xx_dev_to_cfg(&platdev->dev);
1138
1139 if (port->mapbase != 0) 1095 if (port->mapbase != 0)
1140 return 0; 1096 return 0;
1141 1097
1142 if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
1143 printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
1144 cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
1145 return -ERANGE;
1146 }
1147
1148 /* setup info for port */ 1098 /* setup info for port */
1149 port->dev = &platdev->dev; 1099 port->dev = &platdev->dev;
1150 ourport->info = info;
1151 1100
1152 /* Startup sequence is different for s3c64xx and higher SoC's */ 1101 /* Startup sequence is different for s3c64xx and higher SoC's */
1153 if (s3c24xx_serial_has_interrupt_mask(port)) 1102 if (s3c24xx_serial_has_interrupt_mask(port))
1154 s3c24xx_serial_ops.startup = s3c64xx_serial_startup; 1103 s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
1155 1104
1156 /* copy the info in from provided structure */
1157 ourport->port.fifosize = info->fifosize;
1158
1159 dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
1160
1161 port->uartclk = 1; 1105 port->uartclk = 1;
1162 1106
1163 if (cfg->uart_flags & UPF_CONS_FLOW) { 1107 if (cfg->uart_flags & UPF_CONS_FLOW) {
@@ -1215,43 +1159,74 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
1215 struct uart_port *port = s3c24xx_dev_to_port(dev); 1159 struct uart_port *port = s3c24xx_dev_to_port(dev);
1216 struct s3c24xx_uart_port *ourport = to_ourport(port); 1160 struct s3c24xx_uart_port *ourport = to_ourport(port);
1217 1161
1218 return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->clksrc->name); 1162 return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->baudclk->name);
1219} 1163}
1220 1164
1221static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL); 1165static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
1222 1166
1167
1223/* Device driver serial port probe */ 1168/* Device driver serial port probe */
1224 1169
1170static const struct of_device_id s3c24xx_uart_dt_match[];
1225static int probe_index; 1171static int probe_index;
1226 1172
1227int s3c24xx_serial_probe(struct platform_device *dev, 1173static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data(
1228 struct s3c24xx_uart_info *info) 1174 struct platform_device *pdev)
1175{
1176#ifdef CONFIG_OF
1177 if (pdev->dev.of_node) {
1178 const struct of_device_id *match;
1179 match = of_match_node(s3c24xx_uart_dt_match, pdev->dev.of_node);
1180 return (struct s3c24xx_serial_drv_data *)match->data;
1181 }
1182#endif
1183 return (struct s3c24xx_serial_drv_data *)
1184 platform_get_device_id(pdev)->driver_data;
1185}
1186
1187static int s3c24xx_serial_probe(struct platform_device *pdev)
1229{ 1188{
1230 struct s3c24xx_uart_port *ourport; 1189 struct s3c24xx_uart_port *ourport;
1231 int ret; 1190 int ret;
1232 1191
1233 dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index); 1192 dbg("s3c24xx_serial_probe(%p) %d\n", pdev, probe_index);
1234 1193
1235 ourport = &s3c24xx_serial_ports[probe_index]; 1194 ourport = &s3c24xx_serial_ports[probe_index];
1195
1196 ourport->drv_data = s3c24xx_get_driver_data(pdev);
1197 if (!ourport->drv_data) {
1198 dev_err(&pdev->dev, "could not find driver data\n");
1199 return -ENODEV;
1200 }
1201
1202 ourport->info = ourport->drv_data->info;
1203 ourport->cfg = (pdev->dev.platform_data) ?
1204 (struct s3c2410_uartcfg *)pdev->dev.platform_data :
1205 ourport->drv_data->def_cfg;
1206
1207 ourport->port.fifosize = (ourport->info->fifosize) ?
1208 ourport->info->fifosize :
1209 ourport->drv_data->fifosize[probe_index];
1210
1236 probe_index++; 1211 probe_index++;
1237 1212
1238 dbg("%s: initialising port %p...\n", __func__, ourport); 1213 dbg("%s: initialising port %p...\n", __func__, ourport);
1239 1214
1240 ret = s3c24xx_serial_init_port(ourport, info, dev); 1215 ret = s3c24xx_serial_init_port(ourport, pdev);
1241 if (ret < 0) 1216 if (ret < 0)
1242 goto probe_err; 1217 goto probe_err;
1243 1218
1244 dbg("%s: adding port\n", __func__); 1219 dbg("%s: adding port\n", __func__);
1245 uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); 1220 uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
1246 platform_set_drvdata(dev, &ourport->port); 1221 platform_set_drvdata(pdev, &ourport->port);
1247 1222
1248 ret = device_create_file(&dev->dev, &dev_attr_clock_source); 1223 ret = device_create_file(&pdev->dev, &dev_attr_clock_source);
1249 if (ret < 0) 1224 if (ret < 0)
1250 printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__); 1225 dev_err(&pdev->dev, "failed to add clock source attr.\n");
1251 1226
1252 ret = s3c24xx_serial_cpufreq_register(ourport); 1227 ret = s3c24xx_serial_cpufreq_register(ourport);
1253 if (ret < 0) 1228 if (ret < 0)
1254 dev_err(&dev->dev, "failed to add cpufreq notifier\n"); 1229 dev_err(&pdev->dev, "failed to add cpufreq notifier\n");
1255 1230
1256 return 0; 1231 return 0;
1257 1232
@@ -1259,9 +1234,7 @@ int s3c24xx_serial_probe(struct platform_device *dev,
1259 return ret; 1234 return ret;
1260} 1235}
1261 1236
1262EXPORT_SYMBOL_GPL(s3c24xx_serial_probe); 1237static int __devexit s3c24xx_serial_remove(struct platform_device *dev)
1263
1264int __devexit s3c24xx_serial_remove(struct platform_device *dev)
1265{ 1238{
1266 struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); 1239 struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1267 1240
@@ -1274,8 +1247,6 @@ int __devexit s3c24xx_serial_remove(struct platform_device *dev)
1274 return 0; 1247 return 0;
1275} 1248}
1276 1249
1277EXPORT_SYMBOL_GPL(s3c24xx_serial_remove);
1278
1279/* UART power management code */ 1250/* UART power management code */
1280#ifdef CONFIG_PM_SLEEP 1251#ifdef CONFIG_PM_SLEEP
1281static int s3c24xx_serial_suspend(struct device *dev) 1252static int s3c24xx_serial_suspend(struct device *dev)
@@ -1315,41 +1286,6 @@ static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
1315#define SERIAL_SAMSUNG_PM_OPS NULL 1286#define SERIAL_SAMSUNG_PM_OPS NULL
1316#endif /* CONFIG_PM_SLEEP */ 1287#endif /* CONFIG_PM_SLEEP */
1317 1288
1318int s3c24xx_serial_init(struct platform_driver *drv,
1319 struct s3c24xx_uart_info *info)
1320{
1321 dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
1322
1323 drv->driver.pm = SERIAL_SAMSUNG_PM_OPS;
1324
1325 return platform_driver_register(drv);
1326}
1327
1328EXPORT_SYMBOL_GPL(s3c24xx_serial_init);
1329
1330/* module initialisation code */
1331
1332static int __init s3c24xx_serial_modinit(void)
1333{
1334 int ret;
1335
1336 ret = uart_register_driver(&s3c24xx_uart_drv);
1337 if (ret < 0) {
1338 printk(KERN_ERR "failed to register UART driver\n");
1339 return -1;
1340 }
1341
1342 return 0;
1343}
1344
1345static void __exit s3c24xx_serial_modexit(void)
1346{
1347 uart_unregister_driver(&s3c24xx_uart_drv);
1348}
1349
1350module_init(s3c24xx_serial_modinit);
1351module_exit(s3c24xx_serial_modexit);
1352
1353/* Console code */ 1289/* Console code */
1354 1290
1355#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE 1291#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
@@ -1395,12 +1331,13 @@ static void __init
1395s3c24xx_serial_get_options(struct uart_port *port, int *baud, 1331s3c24xx_serial_get_options(struct uart_port *port, int *baud,
1396 int *parity, int *bits) 1332 int *parity, int *bits)
1397{ 1333{
1398 struct s3c24xx_uart_clksrc clksrc;
1399 struct clk *clk; 1334 struct clk *clk;
1400 unsigned int ulcon; 1335 unsigned int ulcon;
1401 unsigned int ucon; 1336 unsigned int ucon;
1402 unsigned int ubrdiv; 1337 unsigned int ubrdiv;
1403 unsigned long rate; 1338 unsigned long rate;
1339 unsigned int clk_sel;
1340 char clk_name[MAX_CLK_NAME_LENGTH];
1404 1341
1405 ulcon = rd_regl(port, S3C2410_ULCON); 1342 ulcon = rd_regl(port, S3C2410_ULCON);
1406 ucon = rd_regl(port, S3C2410_UCON); 1343 ucon = rd_regl(port, S3C2410_UCON);
@@ -1445,44 +1382,21 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
1445 1382
1446 /* now calculate the baud rate */ 1383 /* now calculate the baud rate */
1447 1384
1448 s3c24xx_serial_getsource(port, &clksrc); 1385 clk_sel = s3c24xx_serial_getsource(port);
1386 sprintf(clk_name, "clk_uart_baud%d", clk_sel);
1449 1387
1450 clk = clk_get(port->dev, clksrc.name); 1388 clk = clk_get(port->dev, clk_name);
1451 if (!IS_ERR(clk) && clk != NULL) 1389 if (!IS_ERR(clk) && clk != NULL)
1452 rate = clk_get_rate(clk) / clksrc.divisor; 1390 rate = clk_get_rate(clk);
1453 else 1391 else
1454 rate = 1; 1392 rate = 1;
1455 1393
1456
1457 *baud = rate / (16 * (ubrdiv + 1)); 1394 *baud = rate / (16 * (ubrdiv + 1));
1458 dbg("calculated baud %d\n", *baud); 1395 dbg("calculated baud %d\n", *baud);
1459 } 1396 }
1460 1397
1461} 1398}
1462 1399
1463/* s3c24xx_serial_init_ports
1464 *
1465 * initialise the serial ports from the machine provided initialisation
1466 * data.
1467*/
1468
1469static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
1470{
1471 struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
1472 struct platform_device **platdev_ptr;
1473 int i;
1474
1475 dbg("s3c24xx_serial_init_ports: initialising ports...\n");
1476
1477 platdev_ptr = s3c24xx_uart_devs;
1478
1479 for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
1480 s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
1481 }
1482
1483 return 0;
1484}
1485
1486static int __init 1400static int __init
1487s3c24xx_serial_console_setup(struct console *co, char *options) 1401s3c24xx_serial_console_setup(struct console *co, char *options)
1488{ 1402{
@@ -1526,11 +1440,6 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
1526 return uart_set_options(port, co, baud, parity, bits, flow); 1440 return uart_set_options(port, co, baud, parity, bits, flow);
1527} 1441}
1528 1442
1529/* s3c24xx_serial_initconsole
1530 *
1531 * initialise the console from one of the uart drivers
1532*/
1533
1534static struct console s3c24xx_serial_console = { 1443static struct console s3c24xx_serial_console = {
1535 .name = S3C24XX_SERIAL_NAME, 1444 .name = S3C24XX_SERIAL_NAME,
1536 .device = uart_console_device, 1445 .device = uart_console_device,
@@ -1540,34 +1449,250 @@ static struct console s3c24xx_serial_console = {
1540 .setup = s3c24xx_serial_console_setup, 1449 .setup = s3c24xx_serial_console_setup,
1541 .data = &s3c24xx_uart_drv, 1450 .data = &s3c24xx_uart_drv,
1542}; 1451};
1452#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
1543 1453
1544int s3c24xx_serial_initconsole(struct platform_driver *drv, 1454#ifdef CONFIG_CPU_S3C2410
1545 struct s3c24xx_uart_info **info) 1455static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = {
1456 .info = &(struct s3c24xx_uart_info) {
1457 .name = "Samsung S3C2410 UART",
1458 .type = PORT_S3C2410,
1459 .fifosize = 16,
1460 .rx_fifomask = S3C2410_UFSTAT_RXMASK,
1461 .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT,
1462 .rx_fifofull = S3C2410_UFSTAT_RXFULL,
1463 .tx_fifofull = S3C2410_UFSTAT_TXFULL,
1464 .tx_fifomask = S3C2410_UFSTAT_TXMASK,
1465 .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT,
1466 .def_clk_sel = S3C2410_UCON_CLKSEL0,
1467 .num_clks = 2,
1468 .clksel_mask = S3C2410_UCON_CLKMASK,
1469 .clksel_shift = S3C2410_UCON_CLKSHIFT,
1470 },
1471 .def_cfg = &(struct s3c2410_uartcfg) {
1472 .ucon = S3C2410_UCON_DEFAULT,
1473 .ufcon = S3C2410_UFCON_DEFAULT,
1474 },
1475};
1476#define S3C2410_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2410_serial_drv_data)
1477#else
1478#define S3C2410_SERIAL_DRV_DATA (kernel_ulong_t)NULL
1479#endif
1546 1480
1547{ 1481#ifdef CONFIG_CPU_S3C2412
1548 struct platform_device *dev = s3c24xx_uart_devs[0]; 1482static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = {
1483 .info = &(struct s3c24xx_uart_info) {
1484 .name = "Samsung S3C2412 UART",
1485 .type = PORT_S3C2412,
1486 .fifosize = 64,
1487 .has_divslot = 1,
1488 .rx_fifomask = S3C2440_UFSTAT_RXMASK,
1489 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
1490 .rx_fifofull = S3C2440_UFSTAT_RXFULL,
1491 .tx_fifofull = S3C2440_UFSTAT_TXFULL,
1492 .tx_fifomask = S3C2440_UFSTAT_TXMASK,
1493 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
1494 .def_clk_sel = S3C2410_UCON_CLKSEL2,
1495 .num_clks = 4,
1496 .clksel_mask = S3C2412_UCON_CLKMASK,
1497 .clksel_shift = S3C2412_UCON_CLKSHIFT,
1498 },
1499 .def_cfg = &(struct s3c2410_uartcfg) {
1500 .ucon = S3C2410_UCON_DEFAULT,
1501 .ufcon = S3C2410_UFCON_DEFAULT,
1502 },
1503};
1504#define S3C2412_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2412_serial_drv_data)
1505#else
1506#define S3C2412_SERIAL_DRV_DATA (kernel_ulong_t)NULL
1507#endif
1549 1508
1550 dbg("s3c24xx_serial_initconsole\n"); 1509#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \
1510 defined(CONFIG_CPU_S3C2443)
1511static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
1512 .info = &(struct s3c24xx_uart_info) {
1513 .name = "Samsung S3C2440 UART",
1514 .type = PORT_S3C2440,
1515 .fifosize = 64,
1516 .has_divslot = 1,
1517 .rx_fifomask = S3C2440_UFSTAT_RXMASK,
1518 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
1519 .rx_fifofull = S3C2440_UFSTAT_RXFULL,
1520 .tx_fifofull = S3C2440_UFSTAT_TXFULL,
1521 .tx_fifomask = S3C2440_UFSTAT_TXMASK,
1522 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
1523 .def_clk_sel = S3C2410_UCON_CLKSEL2,
1524 .num_clks = 4,
1525 .clksel_mask = S3C2412_UCON_CLKMASK,
1526 .clksel_shift = S3C2412_UCON_CLKSHIFT,
1527 },
1528 .def_cfg = &(struct s3c2410_uartcfg) {
1529 .ucon = S3C2410_UCON_DEFAULT,
1530 .ufcon = S3C2410_UFCON_DEFAULT,
1531 },
1532};
1533#define S3C2440_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2440_serial_drv_data)
1534#else
1535#define S3C2440_SERIAL_DRV_DATA (kernel_ulong_t)NULL
1536#endif
1551 1537
1552 /* select driver based on the cpu */ 1538#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) || \
1539 defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450) || \
1540 defined(CONFIG_CPU_S5PC100)
1541static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
1542 .info = &(struct s3c24xx_uart_info) {
1543 .name = "Samsung S3C6400 UART",
1544 .type = PORT_S3C6400,
1545 .fifosize = 64,
1546 .has_divslot = 1,
1547 .rx_fifomask = S3C2440_UFSTAT_RXMASK,
1548 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
1549 .rx_fifofull = S3C2440_UFSTAT_RXFULL,
1550 .tx_fifofull = S3C2440_UFSTAT_TXFULL,
1551 .tx_fifomask = S3C2440_UFSTAT_TXMASK,
1552 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
1553 .def_clk_sel = S3C2410_UCON_CLKSEL2,
1554 .num_clks = 4,
1555 .clksel_mask = S3C6400_UCON_CLKMASK,
1556 .clksel_shift = S3C6400_UCON_CLKSHIFT,
1557 },
1558 .def_cfg = &(struct s3c2410_uartcfg) {
1559 .ucon = S3C2410_UCON_DEFAULT,
1560 .ufcon = S3C2410_UFCON_DEFAULT,
1561 },
1562};
1563#define S3C6400_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c6400_serial_drv_data)
1564#else
1565#define S3C6400_SERIAL_DRV_DATA (kernel_ulong_t)NULL
1566#endif
1553 1567
1554 if (dev == NULL) { 1568#ifdef CONFIG_CPU_S5PV210
1555 printk(KERN_ERR "s3c24xx: no devices for console init\n"); 1569static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
1556 return 0; 1570 .info = &(struct s3c24xx_uart_info) {
1557 } 1571 .name = "Samsung S5PV210 UART",
1572 .type = PORT_S3C6400,
1573 .has_divslot = 1,
1574 .rx_fifomask = S5PV210_UFSTAT_RXMASK,
1575 .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT,
1576 .rx_fifofull = S5PV210_UFSTAT_RXFULL,
1577 .tx_fifofull = S5PV210_UFSTAT_TXFULL,
1578 .tx_fifomask = S5PV210_UFSTAT_TXMASK,
1579 .tx_fifoshift = S5PV210_UFSTAT_TXSHIFT,
1580 .def_clk_sel = S3C2410_UCON_CLKSEL0,
1581 .num_clks = 2,
1582 .clksel_mask = S5PV210_UCON_CLKMASK,
1583 .clksel_shift = S5PV210_UCON_CLKSHIFT,
1584 },
1585 .def_cfg = &(struct s3c2410_uartcfg) {
1586 .ucon = S5PV210_UCON_DEFAULT,
1587 .ufcon = S5PV210_UFCON_DEFAULT,
1588 },
1589 .fifosize = { 256, 64, 16, 16 },
1590};
1591#define S5PV210_SERIAL_DRV_DATA ((kernel_ulong_t)&s5pv210_serial_drv_data)
1592#else
1593#define S5PV210_SERIAL_DRV_DATA (kernel_ulong_t)NULL
1594#endif
1558 1595
1559 if (strcmp(dev->name, drv->driver.name) != 0) 1596#ifdef CONFIG_CPU_EXYNOS4210
1560 return 0; 1597static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
1598 .info = &(struct s3c24xx_uart_info) {
1599 .name = "Samsung Exynos4 UART",
1600 .type = PORT_S3C6400,
1601 .has_divslot = 1,
1602 .rx_fifomask = S5PV210_UFSTAT_RXMASK,
1603 .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT,
1604 .rx_fifofull = S5PV210_UFSTAT_RXFULL,
1605 .tx_fifofull = S5PV210_UFSTAT_TXFULL,
1606 .tx_fifomask = S5PV210_UFSTAT_TXMASK,
1607 .tx_fifoshift = S5PV210_UFSTAT_TXSHIFT,
1608 .def_clk_sel = S3C2410_UCON_CLKSEL0,
1609 .num_clks = 1,
1610 .clksel_mask = 0,
1611 .clksel_shift = 0,
1612 },
1613 .def_cfg = &(struct s3c2410_uartcfg) {
1614 .ucon = S5PV210_UCON_DEFAULT,
1615 .ufcon = S5PV210_UFCON_DEFAULT,
1616 .has_fracval = 1,
1617 },
1618 .fifosize = { 256, 64, 16, 16 },
1619};
1620#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data)
1621#else
1622#define EXYNOS4210_SERIAL_DRV_DATA (kernel_ulong_t)NULL
1623#endif
1561 1624
1562 s3c24xx_serial_console.data = &s3c24xx_uart_drv; 1625static struct platform_device_id s3c24xx_serial_driver_ids[] = {
1563 s3c24xx_serial_init_ports(info); 1626 {
1627 .name = "s3c2410-uart",
1628 .driver_data = S3C2410_SERIAL_DRV_DATA,
1629 }, {
1630 .name = "s3c2412-uart",
1631 .driver_data = S3C2412_SERIAL_DRV_DATA,
1632 }, {
1633 .name = "s3c2440-uart",
1634 .driver_data = S3C2440_SERIAL_DRV_DATA,
1635 }, {
1636 .name = "s3c6400-uart",
1637 .driver_data = S3C6400_SERIAL_DRV_DATA,
1638 }, {
1639 .name = "s5pv210-uart",
1640 .driver_data = S5PV210_SERIAL_DRV_DATA,
1641 }, {
1642 .name = "exynos4210-uart",
1643 .driver_data = EXYNOS4210_SERIAL_DRV_DATA,
1644 },
1645 { },
1646};
1647MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids);
1564 1648
1565 register_console(&s3c24xx_serial_console); 1649#ifdef CONFIG_OF
1566 return 0; 1650static const struct of_device_id s3c24xx_uart_dt_match[] = {
1651 { .compatible = "samsung,exynos4210-uart",
1652 .data = (void *)EXYNOS4210_SERIAL_DRV_DATA },
1653 {},
1654};
1655MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
1656#else
1657#define s3c24xx_uart_dt_match NULL
1658#endif
1659
1660static struct platform_driver samsung_serial_driver = {
1661 .probe = s3c24xx_serial_probe,
1662 .remove = __devexit_p(s3c24xx_serial_remove),
1663 .id_table = s3c24xx_serial_driver_ids,
1664 .driver = {
1665 .name = "samsung-uart",
1666 .owner = THIS_MODULE,
1667 .pm = SERIAL_SAMSUNG_PM_OPS,
1668 .of_match_table = s3c24xx_uart_dt_match,
1669 },
1670};
1671
1672/* module initialisation code */
1673
1674static int __init s3c24xx_serial_modinit(void)
1675{
1676 int ret;
1677
1678 ret = uart_register_driver(&s3c24xx_uart_drv);
1679 if (ret < 0) {
1680 printk(KERN_ERR "failed to register UART driver\n");
1681 return -1;
1682 }
1683
1684 return platform_driver_register(&samsung_serial_driver);
1567} 1685}
1568 1686
1569#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */ 1687static void __exit s3c24xx_serial_modexit(void)
1688{
1689 uart_unregister_driver(&s3c24xx_uart_drv);
1690}
1691
1692module_init(s3c24xx_serial_modinit);
1693module_exit(s3c24xx_serial_modexit);
1570 1694
1695MODULE_ALIAS("platform:samsung-uart");
1571MODULE_DESCRIPTION("Samsung SoC Serial port driver"); 1696MODULE_DESCRIPTION("Samsung SoC Serial port driver");
1572MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 1697MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
1573MODULE_LICENSE("GPL v2"); 1698MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index 8e87b788e5c..1a4bca3e417 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -19,20 +19,25 @@ struct s3c24xx_uart_info {
19 unsigned long tx_fifomask; 19 unsigned long tx_fifomask;
20 unsigned long tx_fifoshift; 20 unsigned long tx_fifoshift;
21 unsigned long tx_fifofull; 21 unsigned long tx_fifofull;
22 unsigned int def_clk_sel;
23 unsigned long num_clks;
24 unsigned long clksel_mask;
25 unsigned long clksel_shift;
22 26
23 /* uart port features */ 27 /* uart port features */
24 28
25 unsigned int has_divslot:1; 29 unsigned int has_divslot:1;
26 30
27 /* clock source control */
28
29 int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
30 int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
31
32 /* uart controls */ 31 /* uart controls */
33 int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *); 32 int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
34}; 33};
35 34
35struct s3c24xx_serial_drv_data {
36 struct s3c24xx_uart_info *info;
37 struct s3c2410_uartcfg *def_cfg;
38 unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS];
39};
40
36struct s3c24xx_uart_port { 41struct s3c24xx_uart_port {
37 unsigned char rx_claimed; 42 unsigned char rx_claimed;
38 unsigned char tx_claimed; 43 unsigned char tx_claimed;
@@ -43,10 +48,13 @@ struct s3c24xx_uart_port {
43 unsigned int tx_irq; 48 unsigned int tx_irq;
44 49
45 struct s3c24xx_uart_info *info; 50 struct s3c24xx_uart_info *info;
46 struct s3c24xx_uart_clksrc *clksrc;
47 struct clk *clk; 51 struct clk *clk;
48 struct clk *baudclk; 52 struct clk *baudclk;
49 struct uart_port port; 53 struct uart_port port;
54 struct s3c24xx_serial_drv_data *drv_data;
55
56 /* reference to platform data */
57 struct s3c2410_uartcfg *cfg;
50 58
51#ifdef CONFIG_CPU_FREQ 59#ifdef CONFIG_CPU_FREQ
52 struct notifier_block freq_transition; 60 struct notifier_block freq_transition;
@@ -56,7 +64,6 @@ struct s3c24xx_uart_port {
56/* conversion functions */ 64/* conversion functions */
57 65
58#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev) 66#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
59#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
60 67
61/* register access controls */ 68/* register access controls */
62 69
@@ -69,17 +76,6 @@ struct s3c24xx_uart_port {
69#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg)) 76#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
70#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) 77#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
71 78
72extern int s3c24xx_serial_probe(struct platform_device *dev,
73 struct s3c24xx_uart_info *uart);
74
75extern int __devexit s3c24xx_serial_remove(struct platform_device *dev);
76
77extern int s3c24xx_serial_initconsole(struct platform_driver *drv,
78 struct s3c24xx_uart_info **uart);
79
80extern int s3c24xx_serial_init(struct platform_driver *drv,
81 struct s3c24xx_uart_info *info);
82
83#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG 79#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG
84 80
85extern void printascii(const char *); 81extern void printascii(const char *);