diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 15:09:24 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 15:09:24 -0500 |
commit | 5983faf942f260023e547f3c5f38c1033c35cc9b (patch) | |
tree | f54ce89de5d9f7a05e99948937ac5456df09df30 /drivers/tty/serial/imx.c | |
parent | 21a2cb565a74bf794d343ce22300c5f6c1568ae1 (diff) | |
parent | 995234da19b927f42722d796e8270384f33be11c (diff) |
Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (65 commits)
tty: serial: imx: move del_timer_sync() to avoid potential deadlock
imx: add polled io uart methods
imx: Add save/restore functions for UART control regs
serial/imx: let probing fail for the dt case without a valid alias
serial/imx: propagate error from of_alias_get_id instead of using -ENODEV
tty: serial: imx: Allow UART to be a source for wakeup
serial: driver for m32 arch should not have DEC alpha errata
serial/documentation: fix documented name of DCD cpp symbol
atmel_serial: fix spinlock lockup in RS485 code
tty: Fix memory leak in virtual console when enable unicode translation
serial: use DIV_ROUND_CLOSEST instead of open coding it
serial: add support for 400 and 800 v3 series Titan cards
serial: bfin-uart: Remove ASYNC_CTS_FLOW flag for hardware automatic CTS.
serial: bfin-uart: Enable hardware automatic CTS only when CTS pin is available.
serial: make FSL errata depend on 8250_CONSOLE, not just 8250
serial: add irq handler for Freescale 16550 errata.
serial: manually inline serial8250_handle_port
serial: make 8250 timeout use the specified IRQ handler
serial: export the key functions for an 8250 IRQ handler
serial: clean up parameter passing for 8250 Rx IRQ handling
...
Diffstat (limited to 'drivers/tty/serial/imx.c')
-rw-r--r-- | drivers/tty/serial/imx.c | 148 |
1 files changed, 133 insertions, 15 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 163fc9021f5a..0b7fed746b27 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c | |||
@@ -102,6 +102,7 @@ | |||
102 | #define UCR2_STPB (1<<6) /* Stop */ | 102 | #define UCR2_STPB (1<<6) /* Stop */ |
103 | #define UCR2_WS (1<<5) /* Word size */ | 103 | #define UCR2_WS (1<<5) /* Word size */ |
104 | #define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ | 104 | #define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ |
105 | #define UCR2_ATEN (1<<3) /* Aging Timer Enable */ | ||
105 | #define UCR2_TXEN (1<<2) /* Transmitter enabled */ | 106 | #define UCR2_TXEN (1<<2) /* Transmitter enabled */ |
106 | #define UCR2_RXEN (1<<1) /* Receiver enabled */ | 107 | #define UCR2_RXEN (1<<1) /* Receiver enabled */ |
107 | #define UCR2_SRST (1<<0) /* SW reset */ | 108 | #define UCR2_SRST (1<<0) /* SW reset */ |
@@ -207,6 +208,12 @@ struct imx_port { | |||
207 | struct imx_uart_data *devdata; | 208 | struct imx_uart_data *devdata; |
208 | }; | 209 | }; |
209 | 210 | ||
211 | struct imx_port_ucrs { | ||
212 | unsigned int ucr1; | ||
213 | unsigned int ucr2; | ||
214 | unsigned int ucr3; | ||
215 | }; | ||
216 | |||
210 | #ifdef CONFIG_IRDA | 217 | #ifdef CONFIG_IRDA |
211 | #define USE_IRDA(sport) ((sport)->use_irda) | 218 | #define USE_IRDA(sport) ((sport)->use_irda) |
212 | #else | 219 | #else |
@@ -260,6 +267,27 @@ static inline int is_imx21_uart(struct imx_port *sport) | |||
260 | } | 267 | } |
261 | 268 | ||
262 | /* | 269 | /* |
270 | * Save and restore functions for UCR1, UCR2 and UCR3 registers | ||
271 | */ | ||
272 | static void imx_port_ucrs_save(struct uart_port *port, | ||
273 | struct imx_port_ucrs *ucr) | ||
274 | { | ||
275 | /* save control registers */ | ||
276 | ucr->ucr1 = readl(port->membase + UCR1); | ||
277 | ucr->ucr2 = readl(port->membase + UCR2); | ||
278 | ucr->ucr3 = readl(port->membase + UCR3); | ||
279 | } | ||
280 | |||
281 | static void imx_port_ucrs_restore(struct uart_port *port, | ||
282 | struct imx_port_ucrs *ucr) | ||
283 | { | ||
284 | /* restore control registers */ | ||
285 | writel(ucr->ucr1, port->membase + UCR1); | ||
286 | writel(ucr->ucr2, port->membase + UCR2); | ||
287 | writel(ucr->ucr3, port->membase + UCR3); | ||
288 | } | ||
289 | |||
290 | /* | ||
263 | * Handle any change of modem status signal since we were last called. | 291 | * Handle any change of modem status signal since we were last called. |
264 | */ | 292 | */ |
265 | static void imx_mctrl_check(struct imx_port *sport) | 293 | static void imx_mctrl_check(struct imx_port *sport) |
@@ -566,6 +594,9 @@ static irqreturn_t imx_int(int irq, void *dev_id) | |||
566 | if (sts & USR1_RTSD) | 594 | if (sts & USR1_RTSD) |
567 | imx_rtsint(irq, dev_id); | 595 | imx_rtsint(irq, dev_id); |
568 | 596 | ||
597 | if (sts & USR1_AWAKE) | ||
598 | writel(USR1_AWAKE, sport->port.membase + USR1); | ||
599 | |||
569 | return IRQ_HANDLED; | 600 | return IRQ_HANDLED; |
570 | } | 601 | } |
571 | 602 | ||
@@ -901,6 +932,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
901 | ucr2 |= UCR2_PROE; | 932 | ucr2 |= UCR2_PROE; |
902 | } | 933 | } |
903 | 934 | ||
935 | del_timer_sync(&sport->timer); | ||
936 | |||
904 | /* | 937 | /* |
905 | * Ask the core to calculate the divisor for us. | 938 | * Ask the core to calculate the divisor for us. |
906 | */ | 939 | */ |
@@ -931,8 +964,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
931 | sport->port.ignore_status_mask |= URXD_OVRRUN; | 964 | sport->port.ignore_status_mask |= URXD_OVRRUN; |
932 | } | 965 | } |
933 | 966 | ||
934 | del_timer_sync(&sport->timer); | ||
935 | |||
936 | /* | 967 | /* |
937 | * Update the per-port timeout. | 968 | * Update the per-port timeout. |
938 | */ | 969 | */ |
@@ -1079,6 +1110,70 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser) | |||
1079 | return ret; | 1110 | return ret; |
1080 | } | 1111 | } |
1081 | 1112 | ||
1113 | #if defined(CONFIG_CONSOLE_POLL) | ||
1114 | static int imx_poll_get_char(struct uart_port *port) | ||
1115 | { | ||
1116 | struct imx_port_ucrs old_ucr; | ||
1117 | unsigned int status; | ||
1118 | unsigned char c; | ||
1119 | |||
1120 | /* save control registers */ | ||
1121 | imx_port_ucrs_save(port, &old_ucr); | ||
1122 | |||
1123 | /* disable interrupts */ | ||
1124 | writel(UCR1_UARTEN, port->membase + UCR1); | ||
1125 | writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI), | ||
1126 | port->membase + UCR2); | ||
1127 | writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN), | ||
1128 | port->membase + UCR3); | ||
1129 | |||
1130 | /* poll */ | ||
1131 | do { | ||
1132 | status = readl(port->membase + USR2); | ||
1133 | } while (~status & USR2_RDR); | ||
1134 | |||
1135 | /* read */ | ||
1136 | c = readl(port->membase + URXD0); | ||
1137 | |||
1138 | /* restore control registers */ | ||
1139 | imx_port_ucrs_restore(port, &old_ucr); | ||
1140 | |||
1141 | return c; | ||
1142 | } | ||
1143 | |||
1144 | static void imx_poll_put_char(struct uart_port *port, unsigned char c) | ||
1145 | { | ||
1146 | struct imx_port_ucrs old_ucr; | ||
1147 | unsigned int status; | ||
1148 | |||
1149 | /* save control registers */ | ||
1150 | imx_port_ucrs_save(port, &old_ucr); | ||
1151 | |||
1152 | /* disable interrupts */ | ||
1153 | writel(UCR1_UARTEN, port->membase + UCR1); | ||
1154 | writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI), | ||
1155 | port->membase + UCR2); | ||
1156 | writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN), | ||
1157 | port->membase + UCR3); | ||
1158 | |||
1159 | /* drain */ | ||
1160 | do { | ||
1161 | status = readl(port->membase + USR1); | ||
1162 | } while (~status & USR1_TRDY); | ||
1163 | |||
1164 | /* write */ | ||
1165 | writel(c, port->membase + URTX0); | ||
1166 | |||
1167 | /* flush */ | ||
1168 | do { | ||
1169 | status = readl(port->membase + USR2); | ||
1170 | } while (~status & USR2_TXDC); | ||
1171 | |||
1172 | /* restore control registers */ | ||
1173 | imx_port_ucrs_restore(port, &old_ucr); | ||
1174 | } | ||
1175 | #endif | ||
1176 | |||
1082 | static struct uart_ops imx_pops = { | 1177 | static struct uart_ops imx_pops = { |
1083 | .tx_empty = imx_tx_empty, | 1178 | .tx_empty = imx_tx_empty, |
1084 | .set_mctrl = imx_set_mctrl, | 1179 | .set_mctrl = imx_set_mctrl, |
@@ -1096,6 +1191,10 @@ static struct uart_ops imx_pops = { | |||
1096 | .request_port = imx_request_port, | 1191 | .request_port = imx_request_port, |
1097 | .config_port = imx_config_port, | 1192 | .config_port = imx_config_port, |
1098 | .verify_port = imx_verify_port, | 1193 | .verify_port = imx_verify_port, |
1194 | #if defined(CONFIG_CONSOLE_POLL) | ||
1195 | .poll_get_char = imx_poll_get_char, | ||
1196 | .poll_put_char = imx_poll_put_char, | ||
1197 | #endif | ||
1099 | }; | 1198 | }; |
1100 | 1199 | ||
1101 | static struct imx_port *imx_ports[UART_NR]; | 1200 | static struct imx_port *imx_ports[UART_NR]; |
@@ -1118,13 +1217,14 @@ static void | |||
1118 | imx_console_write(struct console *co, const char *s, unsigned int count) | 1217 | imx_console_write(struct console *co, const char *s, unsigned int count) |
1119 | { | 1218 | { |
1120 | struct imx_port *sport = imx_ports[co->index]; | 1219 | struct imx_port *sport = imx_ports[co->index]; |
1121 | unsigned int old_ucr1, old_ucr2, ucr1; | 1220 | struct imx_port_ucrs old_ucr; |
1221 | unsigned int ucr1; | ||
1122 | 1222 | ||
1123 | /* | 1223 | /* |
1124 | * First, save UCR1/2 and then disable interrupts | 1224 | * First, save UCR1/2/3 and then disable interrupts |
1125 | */ | 1225 | */ |
1126 | ucr1 = old_ucr1 = readl(sport->port.membase + UCR1); | 1226 | imx_port_ucrs_save(&sport->port, &old_ucr); |
1127 | old_ucr2 = readl(sport->port.membase + UCR2); | 1227 | ucr1 = old_ucr.ucr1; |
1128 | 1228 | ||
1129 | if (is_imx1_uart(sport)) | 1229 | if (is_imx1_uart(sport)) |
1130 | ucr1 |= IMX1_UCR1_UARTCLKEN; | 1230 | ucr1 |= IMX1_UCR1_UARTCLKEN; |
@@ -1133,18 +1233,17 @@ imx_console_write(struct console *co, const char *s, unsigned int count) | |||
1133 | 1233 | ||
1134 | writel(ucr1, sport->port.membase + UCR1); | 1234 | writel(ucr1, sport->port.membase + UCR1); |
1135 | 1235 | ||
1136 | writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2); | 1236 | writel(old_ucr.ucr2 | UCR2_TXEN, sport->port.membase + UCR2); |
1137 | 1237 | ||
1138 | uart_console_write(&sport->port, s, count, imx_console_putchar); | 1238 | uart_console_write(&sport->port, s, count, imx_console_putchar); |
1139 | 1239 | ||
1140 | /* | 1240 | /* |
1141 | * Finally, wait for transmitter to become empty | 1241 | * Finally, wait for transmitter to become empty |
1142 | * and restore UCR1/2 | 1242 | * and restore UCR1/2/3 |
1143 | */ | 1243 | */ |
1144 | while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); | 1244 | while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); |
1145 | 1245 | ||
1146 | writel(old_ucr1, sport->port.membase + UCR1); | 1246 | imx_port_ucrs_restore(&sport->port, &old_ucr); |
1147 | writel(old_ucr2, sport->port.membase + UCR2); | ||
1148 | } | 1247 | } |
1149 | 1248 | ||
1150 | /* | 1249 | /* |
@@ -1269,6 +1368,12 @@ static struct uart_driver imx_reg = { | |||
1269 | static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) | 1368 | static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) |
1270 | { | 1369 | { |
1271 | struct imx_port *sport = platform_get_drvdata(dev); | 1370 | struct imx_port *sport = platform_get_drvdata(dev); |
1371 | unsigned int val; | ||
1372 | |||
1373 | /* enable wakeup from i.MX UART */ | ||
1374 | val = readl(sport->port.membase + UCR3); | ||
1375 | val |= UCR3_AWAKEN; | ||
1376 | writel(val, sport->port.membase + UCR3); | ||
1272 | 1377 | ||
1273 | if (sport) | 1378 | if (sport) |
1274 | uart_suspend_port(&imx_reg, &sport->port); | 1379 | uart_suspend_port(&imx_reg, &sport->port); |
@@ -1279,6 +1384,12 @@ static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) | |||
1279 | static int serial_imx_resume(struct platform_device *dev) | 1384 | static int serial_imx_resume(struct platform_device *dev) |
1280 | { | 1385 | { |
1281 | struct imx_port *sport = platform_get_drvdata(dev); | 1386 | struct imx_port *sport = platform_get_drvdata(dev); |
1387 | unsigned int val; | ||
1388 | |||
1389 | /* disable wakeup from i.MX UART */ | ||
1390 | val = readl(sport->port.membase + UCR3); | ||
1391 | val &= ~UCR3_AWAKEN; | ||
1392 | writel(val, sport->port.membase + UCR3); | ||
1282 | 1393 | ||
1283 | if (sport) | 1394 | if (sport) |
1284 | uart_resume_port(&imx_reg, &sport->port); | 1395 | uart_resume_port(&imx_reg, &sport->port); |
@@ -1287,6 +1398,10 @@ static int serial_imx_resume(struct platform_device *dev) | |||
1287 | } | 1398 | } |
1288 | 1399 | ||
1289 | #ifdef CONFIG_OF | 1400 | #ifdef CONFIG_OF |
1401 | /* | ||
1402 | * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it | ||
1403 | * could successfully get all information from dt or a negative errno. | ||
1404 | */ | ||
1290 | static int serial_imx_probe_dt(struct imx_port *sport, | 1405 | static int serial_imx_probe_dt(struct imx_port *sport, |
1291 | struct platform_device *pdev) | 1406 | struct platform_device *pdev) |
1292 | { | 1407 | { |
@@ -1296,12 +1411,13 @@ static int serial_imx_probe_dt(struct imx_port *sport, | |||
1296 | int ret; | 1411 | int ret; |
1297 | 1412 | ||
1298 | if (!np) | 1413 | if (!np) |
1299 | return -ENODEV; | 1414 | /* no device tree device */ |
1415 | return 1; | ||
1300 | 1416 | ||
1301 | ret = of_alias_get_id(np, "serial"); | 1417 | ret = of_alias_get_id(np, "serial"); |
1302 | if (ret < 0) { | 1418 | if (ret < 0) { |
1303 | dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); | 1419 | dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); |
1304 | return -ENODEV; | 1420 | return ret; |
1305 | } | 1421 | } |
1306 | sport->port.line = ret; | 1422 | sport->port.line = ret; |
1307 | 1423 | ||
@@ -1319,7 +1435,7 @@ static int serial_imx_probe_dt(struct imx_port *sport, | |||
1319 | static inline int serial_imx_probe_dt(struct imx_port *sport, | 1435 | static inline int serial_imx_probe_dt(struct imx_port *sport, |
1320 | struct platform_device *pdev) | 1436 | struct platform_device *pdev) |
1321 | { | 1437 | { |
1322 | return -ENODEV; | 1438 | return 1; |
1323 | } | 1439 | } |
1324 | #endif | 1440 | #endif |
1325 | 1441 | ||
@@ -1354,8 +1470,10 @@ static int serial_imx_probe(struct platform_device *pdev) | |||
1354 | return -ENOMEM; | 1470 | return -ENOMEM; |
1355 | 1471 | ||
1356 | ret = serial_imx_probe_dt(sport, pdev); | 1472 | ret = serial_imx_probe_dt(sport, pdev); |
1357 | if (ret == -ENODEV) | 1473 | if (ret > 0) |
1358 | serial_imx_probe_pdata(sport, pdev); | 1474 | serial_imx_probe_pdata(sport, pdev); |
1475 | else if (ret < 0) | ||
1476 | goto free; | ||
1359 | 1477 | ||
1360 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1478 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1361 | if (!res) { | 1479 | if (!res) { |
@@ -1476,7 +1594,7 @@ static int __init imx_serial_init(void) | |||
1476 | if (ret != 0) | 1594 | if (ret != 0) |
1477 | uart_unregister_driver(&imx_reg); | 1595 | uart_unregister_driver(&imx_reg); |
1478 | 1596 | ||
1479 | return 0; | 1597 | return ret; |
1480 | } | 1598 | } |
1481 | 1599 | ||
1482 | static void __exit imx_serial_exit(void) | 1600 | static void __exit imx_serial_exit(void) |