aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorThomas Abraham <thomas.abraham@linaro.org>2011-08-10 06:21:19 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-08-23 13:48:31 -0400
commit88bb4ea14c72f89c5265029c1891e5eb6521cc0f (patch)
tree586608107cf9f69f214e252bb51013a11e1be734 /drivers
parent47918f055851d3faae2a62d406b5d065b579a1a3 (diff)
serial: samsung: Add unified interrupt handler for s3c64xx and later SoC's
s3c64xx and later SoC's include the interrupt mask and pending registers in the uart controller, unlike the s3c24xx SoC's which have these registers in the interrupt controller. When the mask and pending registers are part of the uart controller, a unified interrupt handler can handle the tx/rx interrupt. With this, the static reservation of interrupt numbers for the uart tx/rx/err interrupts in the linux irq space is not required and simplifies adding device tree support. Suggested-by: Grant Likely <grant.likely@secretlab.ca> CC: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org> Acked-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
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)))