diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/tty/serial/samsung.c | 107 | ||||
-rw-r--r-- | drivers/tty/serial/samsung.h | 1 |
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 | */ | ||
91 | static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port) | ||
92 | { | ||
93 | return to_ourport(port)->info->type == PORT_S3C6400; | ||
94 | } | ||
95 | |||
86 | static void s3c24xx_serial_rx_enable(struct uart_port *port) | 96 | static 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 | |||
150 | static void s3c24xx_serial_stop_rx(struct uart_port *port) | 167 | static 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.*/ | ||
345 | static 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 | |||
323 | static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) | 366 | static 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 | ||
393 | static int s3c24xx_serial_startup(struct uart_port *port) | 443 | static 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 | ||
489 | static 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 | ||
441 | static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, | 518 | static 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 | |||
883 | static struct uart_driver s3c24xx_uart_drv = { | 959 | static 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))) |