aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tty/serial/samsung.c107
-rw-r--r--drivers/tty/serial/samsung.h1
2 files changed, 96 insertions, 12 deletions
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index afc629423152..9b8465487253 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -83,6 +83,16 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
83 return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE); 83 return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
84} 84}
85 85
86/*
87 * s3c64xx and later SoC's include the interrupt mask and status registers in
88 * the controller itself, unlike the s3c24xx SoC's which have these registers
89 * in the interrupt controller. Check if the port type is s3c64xx or higher.
90 */
91static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
92{
93 return to_ourport(port)->info->type == PORT_S3C6400;
94}
95
86static void s3c24xx_serial_rx_enable(struct uart_port *port) 96static void s3c24xx_serial_rx_enable(struct uart_port *port)
87{ 97{
88 unsigned long flags; 98 unsigned long flags;
@@ -126,7 +136,11 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
126 struct s3c24xx_uart_port *ourport = to_ourport(port); 136 struct s3c24xx_uart_port *ourport = to_ourport(port);
127 137
128 if (tx_enabled(port)) { 138 if (tx_enabled(port)) {
129 disable_irq_nosync(ourport->tx_irq); 139 if (s3c24xx_serial_has_interrupt_mask(port))
140 __set_bit(S3C64XX_UINTM_TXD,
141 portaddrl(port, S3C64XX_UINTM));
142 else
143 disable_irq_nosync(ourport->tx_irq);
130 tx_enabled(port) = 0; 144 tx_enabled(port) = 0;
131 if (port->flags & UPF_CONS_FLOW) 145 if (port->flags & UPF_CONS_FLOW)
132 s3c24xx_serial_rx_enable(port); 146 s3c24xx_serial_rx_enable(port);
@@ -141,19 +155,26 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
141 if (port->flags & UPF_CONS_FLOW) 155 if (port->flags & UPF_CONS_FLOW)
142 s3c24xx_serial_rx_disable(port); 156 s3c24xx_serial_rx_disable(port);
143 157
144 enable_irq(ourport->tx_irq); 158 if (s3c24xx_serial_has_interrupt_mask(port))
159 __clear_bit(S3C64XX_UINTM_TXD,
160 portaddrl(port, S3C64XX_UINTM));
161 else
162 enable_irq(ourport->tx_irq);
145 tx_enabled(port) = 1; 163 tx_enabled(port) = 1;
146 } 164 }
147} 165}
148 166
149
150static void s3c24xx_serial_stop_rx(struct uart_port *port) 167static void s3c24xx_serial_stop_rx(struct uart_port *port)
151{ 168{
152 struct s3c24xx_uart_port *ourport = to_ourport(port); 169 struct s3c24xx_uart_port *ourport = to_ourport(port);
153 170
154 if (rx_enabled(port)) { 171 if (rx_enabled(port)) {
155 dbg("s3c24xx_serial_stop_rx: port=%p\n", port); 172 dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
156 disable_irq_nosync(ourport->rx_irq); 173 if (s3c24xx_serial_has_interrupt_mask(port))
174 __set_bit(S3C64XX_UINTM_RXD,
175 portaddrl(port, S3C64XX_UINTM));
176 else
177 disable_irq_nosync(ourport->rx_irq);
157 rx_enabled(port) = 0; 178 rx_enabled(port) = 0;
158 } 179 }
159} 180}
@@ -320,6 +341,28 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
320 return IRQ_HANDLED; 341 return IRQ_HANDLED;
321} 342}
322 343
344/* interrupt handler for s3c64xx and later SoC's.*/
345static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
346{
347 struct s3c24xx_uart_port *ourport = id;
348 struct uart_port *port = &ourport->port;
349 unsigned int pend = rd_regl(port, S3C64XX_UINTP);
350 unsigned long flags;
351 irqreturn_t ret = IRQ_HANDLED;
352
353 spin_lock_irqsave(&port->lock, flags);
354 if (pend & S3C64XX_UINTM_RXD_MSK) {
355 ret = s3c24xx_serial_rx_chars(irq, id);
356 wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK);
357 }
358 if (pend & S3C64XX_UINTM_TXD_MSK) {
359 ret = s3c24xx_serial_tx_chars(irq, id);
360 wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK);
361 }
362 spin_unlock_irqrestore(&port->lock, flags);
363 return ret;
364}
365
323static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) 366static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
324{ 367{
325 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); 368 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
@@ -377,18 +420,25 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
377 struct s3c24xx_uart_port *ourport = to_ourport(port); 420 struct s3c24xx_uart_port *ourport = to_ourport(port);
378 421
379 if (ourport->tx_claimed) { 422 if (ourport->tx_claimed) {
380 free_irq(ourport->tx_irq, ourport); 423 if (!s3c24xx_serial_has_interrupt_mask(port))
424 free_irq(ourport->tx_irq, ourport);
381 tx_enabled(port) = 0; 425 tx_enabled(port) = 0;
382 ourport->tx_claimed = 0; 426 ourport->tx_claimed = 0;
383 } 427 }
384 428
385 if (ourport->rx_claimed) { 429 if (ourport->rx_claimed) {
386 free_irq(ourport->rx_irq, ourport); 430 if (!s3c24xx_serial_has_interrupt_mask(port))
431 free_irq(ourport->rx_irq, ourport);
387 ourport->rx_claimed = 0; 432 ourport->rx_claimed = 0;
388 rx_enabled(port) = 0; 433 rx_enabled(port) = 0;
389 } 434 }
390}
391 435
436 /* Clear pending interrupts and mask all interrupts */
437 if (s3c24xx_serial_has_interrupt_mask(port)) {
438 wr_regl(port, S3C64XX_UINTP, 0xf);
439 wr_regl(port, S3C64XX_UINTM, 0xf);
440 }
441}
392 442
393static int s3c24xx_serial_startup(struct uart_port *port) 443static int s3c24xx_serial_startup(struct uart_port *port)
394{ 444{
@@ -436,6 +486,33 @@ static int s3c24xx_serial_startup(struct uart_port *port)
436 return ret; 486 return ret;
437} 487}
438 488
489static int s3c64xx_serial_startup(struct uart_port *port)
490{
491 struct s3c24xx_uart_port *ourport = to_ourport(port);
492 int ret;
493
494 dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
495 port->mapbase, port->membase);
496
497 ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
498 s3c24xx_serial_portname(port), ourport);
499 if (ret) {
500 printk(KERN_ERR "cannot get irq %d\n", port->irq);
501 return ret;
502 }
503
504 /* For compatibility with s3c24xx Soc's */
505 rx_enabled(port) = 1;
506 ourport->rx_claimed = 1;
507 tx_enabled(port) = 0;
508 ourport->tx_claimed = 1;
509
510 /* Enable Rx Interrupt */
511 __clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
512 dbg("s3c64xx_serial_startup ok\n");
513 return ret;
514}
515
439/* power power management control */ 516/* power power management control */
440 517
441static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, 518static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@ -879,7 +956,6 @@ static struct uart_ops s3c24xx_serial_ops = {
879 .verify_port = s3c24xx_serial_verify_port, 956 .verify_port = s3c24xx_serial_verify_port,
880}; 957};
881 958
882
883static struct uart_driver s3c24xx_uart_drv = { 959static struct uart_driver s3c24xx_uart_drv = {
884 .owner = THIS_MODULE, 960 .owner = THIS_MODULE,
885 .driver_name = "s3c2410_serial", 961 .driver_name = "s3c2410_serial",
@@ -895,7 +971,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
895 .port = { 971 .port = {
896 .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock), 972 .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
897 .iotype = UPIO_MEM, 973 .iotype = UPIO_MEM,
898 .irq = IRQ_S3CUART_RX0,
899 .uartclk = 0, 974 .uartclk = 0,
900 .fifosize = 16, 975 .fifosize = 16,
901 .ops = &s3c24xx_serial_ops, 976 .ops = &s3c24xx_serial_ops,
@@ -907,7 +982,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
907 .port = { 982 .port = {
908 .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock), 983 .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
909 .iotype = UPIO_MEM, 984 .iotype = UPIO_MEM,
910 .irq = IRQ_S3CUART_RX1,
911 .uartclk = 0, 985 .uartclk = 0,
912 .fifosize = 16, 986 .fifosize = 16,
913 .ops = &s3c24xx_serial_ops, 987 .ops = &s3c24xx_serial_ops,
@@ -921,7 +995,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
921 .port = { 995 .port = {
922 .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock), 996 .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
923 .iotype = UPIO_MEM, 997 .iotype = UPIO_MEM,
924 .irq = IRQ_S3CUART_RX2,
925 .uartclk = 0, 998 .uartclk = 0,
926 .fifosize = 16, 999 .fifosize = 16,
927 .ops = &s3c24xx_serial_ops, 1000 .ops = &s3c24xx_serial_ops,
@@ -935,7 +1008,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
935 .port = { 1008 .port = {
936 .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock), 1009 .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
937 .iotype = UPIO_MEM, 1010 .iotype = UPIO_MEM,
938 .irq = IRQ_S3CUART_RX3,
939 .uartclk = 0, 1011 .uartclk = 0,
940 .fifosize = 16, 1012 .fifosize = 16,
941 .ops = &s3c24xx_serial_ops, 1013 .ops = &s3c24xx_serial_ops,
@@ -1077,6 +1149,10 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
1077 port->dev = &platdev->dev; 1149 port->dev = &platdev->dev;
1078 ourport->info = info; 1150 ourport->info = info;
1079 1151
1152 /* Startup sequence is different for s3c64xx and higher SoC's */
1153 if (s3c24xx_serial_has_interrupt_mask(port))
1154 s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
1155
1080 /* copy the info in from provided structure */ 1156 /* copy the info in from provided structure */
1081 ourport->port.fifosize = info->fifosize; 1157 ourport->port.fifosize = info->fifosize;
1082 1158
@@ -1116,6 +1192,13 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
1116 1192
1117 ourport->clk = clk_get(&platdev->dev, "uart"); 1193 ourport->clk = clk_get(&platdev->dev, "uart");
1118 1194
1195 /* Keep all interrupts masked and cleared */
1196 if (s3c24xx_serial_has_interrupt_mask(port)) {
1197 wr_regl(port, S3C64XX_UINTM, 0xf);
1198 wr_regl(port, S3C64XX_UINTP, 0xf);
1199 wr_regl(port, S3C64XX_UINTSP, 0xf);
1200 }
1201
1119 dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n", 1202 dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
1120 port->mapbase, port->membase, port->irq, 1203 port->mapbase, port->membase, port->irq,
1121 ourport->rx_irq, ourport->tx_irq, port->uartclk); 1204 ourport->rx_irq, ourport->tx_irq, port->uartclk);
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index a69d9a54be94..8e87b788e5c6 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -61,6 +61,7 @@ struct s3c24xx_uart_port {
61/* register access controls */ 61/* register access controls */
62 62
63#define portaddr(port, reg) ((port)->membase + (reg)) 63#define portaddr(port, reg) ((port)->membase + (reg))
64#define portaddrl(port, reg) ((unsigned long *)((port)->membase + (reg)))
64 65
65#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg))) 66#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
66#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg))) 67#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))