diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2007-02-21 12:17:28 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-02-21 19:50:45 -0500 |
commit | 0970769aceb9bccf038f5dba72379f68431f94db (patch) | |
tree | 238be13350a38d3f50b906b4c619d722b9bc7541 | |
parent | 5ce704f877057e257ecb9f5cdec6c4aa5c0d064c (diff) |
[SERIAL] serial_txx9 driver update
* Use platform_device.
* Fix and cleanup suspend/resume/initialization codes.
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Acked-by: Alan Cox <alan@redhat.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | drivers/serial/serial_txx9.c | 276 |
1 files changed, 184 insertions, 92 deletions
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index f4440d329310..509ace7e6881 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c | |||
@@ -38,6 +38,8 @@ | |||
38 | * Fix some spin_locks. | 38 | * Fix some spin_locks. |
39 | * Do not call uart_add_one_port for absent ports. | 39 | * Do not call uart_add_one_port for absent ports. |
40 | * 1.07 Use CONFIG_SERIAL_TXX9_NR_UARTS. Cleanup. | 40 | * 1.07 Use CONFIG_SERIAL_TXX9_NR_UARTS. Cleanup. |
41 | * 1.08 Use platform_device. | ||
42 | * Fix and cleanup suspend/resume/initialization codes. | ||
41 | */ | 43 | */ |
42 | 44 | ||
43 | #if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | 45 | #if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) |
@@ -50,7 +52,7 @@ | |||
50 | #include <linux/console.h> | 52 | #include <linux/console.h> |
51 | #include <linux/sysrq.h> | 53 | #include <linux/sysrq.h> |
52 | #include <linux/delay.h> | 54 | #include <linux/delay.h> |
53 | #include <linux/device.h> | 55 | #include <linux/platform_device.h> |
54 | #include <linux/pci.h> | 56 | #include <linux/pci.h> |
55 | #include <linux/tty.h> | 57 | #include <linux/tty.h> |
56 | #include <linux/tty_flip.h> | 58 | #include <linux/tty_flip.h> |
@@ -60,7 +62,7 @@ | |||
60 | 62 | ||
61 | #include <asm/io.h> | 63 | #include <asm/io.h> |
62 | 64 | ||
63 | static char *serial_version = "1.07"; | 65 | static char *serial_version = "1.08"; |
64 | static char *serial_name = "TX39/49 Serial driver"; | 66 | static char *serial_name = "TX39/49 Serial driver"; |
65 | 67 | ||
66 | #define PASS_LIMIT 256 | 68 | #define PASS_LIMIT 256 |
@@ -94,12 +96,7 @@ static char *serial_name = "TX39/49 Serial driver"; | |||
94 | 96 | ||
95 | struct uart_txx9_port { | 97 | struct uart_txx9_port { |
96 | struct uart_port port; | 98 | struct uart_port port; |
97 | 99 | /* No additional info for now */ | |
98 | /* | ||
99 | * We provide a per-port pm hook. | ||
100 | */ | ||
101 | void (*pm)(struct uart_port *port, | ||
102 | unsigned int state, unsigned int old); | ||
103 | }; | 100 | }; |
104 | 101 | ||
105 | #define TXX9_REGION_SIZE 0x24 | 102 | #define TXX9_REGION_SIZE 0x24 |
@@ -277,6 +274,31 @@ static void serial_txx9_enable_ms(struct uart_port *port) | |||
277 | /* TXX9-SIO can not control DTR... */ | 274 | /* TXX9-SIO can not control DTR... */ |
278 | } | 275 | } |
279 | 276 | ||
277 | static void serial_txx9_initialize(struct uart_port *port) | ||
278 | { | ||
279 | struct uart_txx9_port *up = (struct uart_txx9_port *)port; | ||
280 | unsigned int tmout = 10000; | ||
281 | |||
282 | sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST); | ||
283 | /* TX4925 BUG WORKAROUND. Accessing SIOC register | ||
284 | * immediately after soft reset causes bus error. */ | ||
285 | mmiowb(); | ||
286 | udelay(1); | ||
287 | while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout) | ||
288 | udelay(1); | ||
289 | /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ | ||
290 | sio_set(up, TXX9_SIFCR, | ||
291 | TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1); | ||
292 | /* initial settings */ | ||
293 | sio_out(up, TXX9_SILCR, | ||
294 | TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT | | ||
295 | ((up->port.flags & UPF_TXX9_USE_SCLK) ? | ||
296 | TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG)); | ||
297 | sio_quot_set(up, uart_get_divisor(port, 9600)); | ||
298 | sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */); | ||
299 | sio_out(up, TXX9_SIDICR, 0); | ||
300 | } | ||
301 | |||
280 | static inline void | 302 | static inline void |
281 | receive_chars(struct uart_txx9_port *up, unsigned int *status) | 303 | receive_chars(struct uart_txx9_port *up, unsigned int *status) |
282 | { | 304 | { |
@@ -657,9 +679,8 @@ static void | |||
657 | serial_txx9_pm(struct uart_port *port, unsigned int state, | 679 | serial_txx9_pm(struct uart_port *port, unsigned int state, |
658 | unsigned int oldstate) | 680 | unsigned int oldstate) |
659 | { | 681 | { |
660 | struct uart_txx9_port *up = (struct uart_txx9_port *)port; | 682 | if (state == 0) |
661 | if (up->pm) | 683 | serial_txx9_initialize(port); |
662 | up->pm(port, state, oldstate); | ||
663 | } | 684 | } |
664 | 685 | ||
665 | static int serial_txx9_request_resource(struct uart_txx9_port *up) | 686 | static int serial_txx9_request_resource(struct uart_txx9_port *up) |
@@ -732,7 +753,6 @@ static int serial_txx9_request_port(struct uart_port *port) | |||
732 | static void serial_txx9_config_port(struct uart_port *port, int uflags) | 753 | static void serial_txx9_config_port(struct uart_port *port, int uflags) |
733 | { | 754 | { |
734 | struct uart_txx9_port *up = (struct uart_txx9_port *)port; | 755 | struct uart_txx9_port *up = (struct uart_txx9_port *)port; |
735 | unsigned long flags; | ||
736 | int ret; | 756 | int ret; |
737 | 757 | ||
738 | /* | 758 | /* |
@@ -749,30 +769,7 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags) | |||
749 | if (up->port.line == up->port.cons->index) | 769 | if (up->port.line == up->port.cons->index) |
750 | return; | 770 | return; |
751 | #endif | 771 | #endif |
752 | spin_lock_irqsave(&up->port.lock, flags); | 772 | serial_txx9_initialize(port); |
753 | /* | ||
754 | * Reset the UART. | ||
755 | */ | ||
756 | sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST); | ||
757 | #ifdef CONFIG_CPU_TX49XX | ||
758 | /* TX4925 BUG WORKAROUND. Accessing SIOC register | ||
759 | * immediately after soft reset causes bus error. */ | ||
760 | iob(); | ||
761 | udelay(1); | ||
762 | #endif | ||
763 | while (sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) | ||
764 | ; | ||
765 | /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ | ||
766 | sio_set(up, TXX9_SIFCR, | ||
767 | TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1); | ||
768 | /* initial settings */ | ||
769 | sio_out(up, TXX9_SILCR, | ||
770 | TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT | | ||
771 | ((up->port.flags & UPF_TXX9_USE_SCLK) ? | ||
772 | TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG)); | ||
773 | sio_quot_set(up, uart_get_divisor(port, 9600)); | ||
774 | sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */); | ||
775 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
776 | } | 773 | } |
777 | 774 | ||
778 | static int | 775 | static int |
@@ -818,7 +815,8 @@ static struct uart_ops serial_txx9_pops = { | |||
818 | 815 | ||
819 | static struct uart_txx9_port serial_txx9_ports[UART_NR]; | 816 | static struct uart_txx9_port serial_txx9_ports[UART_NR]; |
820 | 817 | ||
821 | static void __init serial_txx9_register_ports(struct uart_driver *drv) | 818 | static void __init serial_txx9_register_ports(struct uart_driver *drv, |
819 | struct device *dev) | ||
822 | { | 820 | { |
823 | int i; | 821 | int i; |
824 | 822 | ||
@@ -827,6 +825,7 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv) | |||
827 | 825 | ||
828 | up->port.line = i; | 826 | up->port.line = i; |
829 | up->port.ops = &serial_txx9_pops; | 827 | up->port.ops = &serial_txx9_pops; |
828 | up->port.dev = dev; | ||
830 | if (up->port.iobase || up->port.mapbase) | 829 | if (up->port.iobase || up->port.mapbase) |
831 | uart_add_one_port(drv, &up->port); | 830 | uart_add_one_port(drv, &up->port); |
832 | } | 831 | } |
@@ -898,7 +897,7 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count) | |||
898 | sio_out(up, TXX9_SIDICR, ier); | 897 | sio_out(up, TXX9_SIDICR, ier); |
899 | } | 898 | } |
900 | 899 | ||
901 | static int serial_txx9_console_setup(struct console *co, char *options) | 900 | static int __init serial_txx9_console_setup(struct console *co, char *options) |
902 | { | 901 | { |
903 | struct uart_port *port; | 902 | struct uart_port *port; |
904 | struct uart_txx9_port *up; | 903 | struct uart_txx9_port *up; |
@@ -919,17 +918,7 @@ static int serial_txx9_console_setup(struct console *co, char *options) | |||
919 | if (!port->ops) | 918 | if (!port->ops) |
920 | return -ENODEV; | 919 | return -ENODEV; |
921 | 920 | ||
922 | /* | 921 | serial_txx9_initialize(&up->port); |
923 | * Disable UART interrupts, set DTR and RTS high | ||
924 | * and set speed. | ||
925 | */ | ||
926 | sio_out(up, TXX9_SIDICR, 0); | ||
927 | /* initial settings */ | ||
928 | sio_out(up, TXX9_SILCR, | ||
929 | TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT | | ||
930 | ((port->flags & UPF_TXX9_USE_SCLK) ? | ||
931 | TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG)); | ||
932 | sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */); | ||
933 | 922 | ||
934 | if (options) | 923 | if (options) |
935 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 924 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
@@ -981,31 +970,6 @@ int __init early_serial_txx9_setup(struct uart_port *port) | |||
981 | return 0; | 970 | return 0; |
982 | } | 971 | } |
983 | 972 | ||
984 | #ifdef ENABLE_SERIAL_TXX9_PCI | ||
985 | #ifdef CONFIG_PM | ||
986 | /** | ||
987 | * serial_txx9_suspend_port - suspend one serial port | ||
988 | * @line: serial line number | ||
989 | * | ||
990 | * Suspend one serial port. | ||
991 | */ | ||
992 | static void serial_txx9_suspend_port(int line) | ||
993 | { | ||
994 | uart_suspend_port(&serial_txx9_reg, &serial_txx9_ports[line].port); | ||
995 | } | ||
996 | |||
997 | /** | ||
998 | * serial_txx9_resume_port - resume one serial port | ||
999 | * @line: serial line number | ||
1000 | * | ||
1001 | * Resume one serial port. | ||
1002 | */ | ||
1003 | static void serial_txx9_resume_port(int line) | ||
1004 | { | ||
1005 | uart_resume_port(&serial_txx9_reg, &serial_txx9_ports[line].port); | ||
1006 | } | ||
1007 | #endif | ||
1008 | |||
1009 | static DEFINE_MUTEX(serial_txx9_mutex); | 973 | static DEFINE_MUTEX(serial_txx9_mutex); |
1010 | 974 | ||
1011 | /** | 975 | /** |
@@ -1028,8 +992,18 @@ static int __devinit serial_txx9_register_port(struct uart_port *port) | |||
1028 | mutex_lock(&serial_txx9_mutex); | 992 | mutex_lock(&serial_txx9_mutex); |
1029 | for (i = 0; i < UART_NR; i++) { | 993 | for (i = 0; i < UART_NR; i++) { |
1030 | uart = &serial_txx9_ports[i]; | 994 | uart = &serial_txx9_ports[i]; |
1031 | if (!(uart->port.iobase || uart->port.mapbase)) | 995 | if (uart_match_port(&uart->port, port)) { |
996 | uart_remove_one_port(&serial_txx9_reg, &uart->port); | ||
1032 | break; | 997 | break; |
998 | } | ||
999 | } | ||
1000 | if (i == UART_NR) { | ||
1001 | /* Find unused port */ | ||
1002 | for (i = 0; i < UART_NR; i++) { | ||
1003 | uart = &serial_txx9_ports[i]; | ||
1004 | if (!(uart->port.iobase || uart->port.mapbase)) | ||
1005 | break; | ||
1006 | } | ||
1033 | } | 1007 | } |
1034 | if (i < UART_NR) { | 1008 | if (i < UART_NR) { |
1035 | uart->port.iobase = port->iobase; | 1009 | uart->port.iobase = port->iobase; |
@@ -1072,6 +1046,95 @@ static void __devexit serial_txx9_unregister_port(int line) | |||
1072 | } | 1046 | } |
1073 | 1047 | ||
1074 | /* | 1048 | /* |
1049 | * Register a set of serial devices attached to a platform device. | ||
1050 | */ | ||
1051 | static int __devinit serial_txx9_probe(struct platform_device *dev) | ||
1052 | { | ||
1053 | struct uart_port *p = dev->dev.platform_data; | ||
1054 | struct uart_port port; | ||
1055 | int ret, i; | ||
1056 | |||
1057 | memset(&port, 0, sizeof(struct uart_port)); | ||
1058 | for (i = 0; p && p->uartclk != 0; p++, i++) { | ||
1059 | port.iobase = p->iobase; | ||
1060 | port.membase = p->membase; | ||
1061 | port.irq = p->irq; | ||
1062 | port.uartclk = p->uartclk; | ||
1063 | port.iotype = p->iotype; | ||
1064 | port.flags = p->flags; | ||
1065 | port.mapbase = p->mapbase; | ||
1066 | port.dev = &dev->dev; | ||
1067 | ret = serial_txx9_register_port(&port); | ||
1068 | if (ret < 0) { | ||
1069 | dev_err(&dev->dev, "unable to register port at index %d " | ||
1070 | "(IO%x MEM%lx IRQ%d): %d\n", i, | ||
1071 | p->iobase, p->mapbase, p->irq, ret); | ||
1072 | } | ||
1073 | } | ||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
1077 | /* | ||
1078 | * Remove serial ports registered against a platform device. | ||
1079 | */ | ||
1080 | static int __devexit serial_txx9_remove(struct platform_device *dev) | ||
1081 | { | ||
1082 | int i; | ||
1083 | |||
1084 | for (i = 0; i < UART_NR; i++) { | ||
1085 | struct uart_txx9_port *up = &serial_txx9_ports[i]; | ||
1086 | |||
1087 | if (up->port.dev == &dev->dev) | ||
1088 | serial_txx9_unregister_port(i); | ||
1089 | } | ||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | #ifdef CONFIG_PM | ||
1094 | static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state) | ||
1095 | { | ||
1096 | int i; | ||
1097 | |||
1098 | for (i = 0; i < UART_NR; i++) { | ||
1099 | struct uart_txx9_port *up = &serial_txx9_ports[i]; | ||
1100 | |||
1101 | if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) | ||
1102 | uart_suspend_port(&serial_txx9_reg, &up->port); | ||
1103 | } | ||
1104 | |||
1105 | return 0; | ||
1106 | } | ||
1107 | |||
1108 | static int serial_txx9_resume(struct platform_device *dev) | ||
1109 | { | ||
1110 | int i; | ||
1111 | |||
1112 | for (i = 0; i < UART_NR; i++) { | ||
1113 | struct uart_txx9_port *up = &serial_txx9_ports[i]; | ||
1114 | |||
1115 | if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) | ||
1116 | uart_resume_port(&serial_txx9_reg, &up->port); | ||
1117 | } | ||
1118 | |||
1119 | return 0; | ||
1120 | } | ||
1121 | #endif | ||
1122 | |||
1123 | static struct platform_driver serial_txx9_plat_driver = { | ||
1124 | .probe = serial_txx9_probe, | ||
1125 | .remove = __devexit_p(serial_txx9_remove), | ||
1126 | #ifdef CONFIG_PM | ||
1127 | .suspend = serial_txx9_suspend, | ||
1128 | .resume = serial_txx9_resume, | ||
1129 | #endif | ||
1130 | .driver = { | ||
1131 | .name = "serial_txx9", | ||
1132 | .owner = THIS_MODULE, | ||
1133 | }, | ||
1134 | }; | ||
1135 | |||
1136 | #ifdef ENABLE_SERIAL_TXX9_PCI | ||
1137 | /* | ||
1075 | * Probe one serial board. Unfortunately, there is no rhyme nor reason | 1138 | * Probe one serial board. Unfortunately, there is no rhyme nor reason |
1076 | * to the arrangement of serial ports on a PCI card. | 1139 | * to the arrangement of serial ports on a PCI card. |
1077 | */ | 1140 | */ |
@@ -1097,20 +1160,22 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent) | |||
1097 | line = serial_txx9_register_port(&port); | 1160 | line = serial_txx9_register_port(&port); |
1098 | if (line < 0) { | 1161 | if (line < 0) { |
1099 | printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line); | 1162 | printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line); |
1163 | pci_disable_device(dev); | ||
1164 | return line; | ||
1100 | } | 1165 | } |
1101 | pci_set_drvdata(dev, (void *)(long)line); | 1166 | pci_set_drvdata(dev, &serial_txx9_ports[line]); |
1102 | 1167 | ||
1103 | return 0; | 1168 | return 0; |
1104 | } | 1169 | } |
1105 | 1170 | ||
1106 | static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev) | 1171 | static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev) |
1107 | { | 1172 | { |
1108 | int line = (int)(long)pci_get_drvdata(dev); | 1173 | struct uart_txx9_port *up = pci_get_drvdata(dev); |
1109 | 1174 | ||
1110 | pci_set_drvdata(dev, NULL); | 1175 | pci_set_drvdata(dev, NULL); |
1111 | 1176 | ||
1112 | if (line) { | 1177 | if (up) { |
1113 | serial_txx9_unregister_port(line); | 1178 | serial_txx9_unregister_port(up->port.line); |
1114 | pci_disable_device(dev); | 1179 | pci_disable_device(dev); |
1115 | } | 1180 | } |
1116 | } | 1181 | } |
@@ -1118,10 +1183,10 @@ static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev) | |||
1118 | #ifdef CONFIG_PM | 1183 | #ifdef CONFIG_PM |
1119 | static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) | 1184 | static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) |
1120 | { | 1185 | { |
1121 | int line = (int)(long)pci_get_drvdata(dev); | 1186 | struct uart_txx9_port *up = pci_get_drvdata(dev); |
1122 | 1187 | ||
1123 | if (line) | 1188 | if (up) |
1124 | serial_txx9_suspend_port(line); | 1189 | uart_suspend_port(&serial_txx9_reg, &up->port); |
1125 | pci_save_state(dev); | 1190 | pci_save_state(dev); |
1126 | pci_set_power_state(dev, pci_choose_state(dev, state)); | 1191 | pci_set_power_state(dev, pci_choose_state(dev, state)); |
1127 | return 0; | 1192 | return 0; |
@@ -1129,15 +1194,12 @@ static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) | |||
1129 | 1194 | ||
1130 | static int pciserial_txx9_resume_one(struct pci_dev *dev) | 1195 | static int pciserial_txx9_resume_one(struct pci_dev *dev) |
1131 | { | 1196 | { |
1132 | int line = (int)(long)pci_get_drvdata(dev); | 1197 | struct uart_txx9_port *up = pci_get_drvdata(dev); |
1133 | 1198 | ||
1134 | pci_set_power_state(dev, PCI_D0); | 1199 | pci_set_power_state(dev, PCI_D0); |
1135 | pci_restore_state(dev); | 1200 | pci_restore_state(dev); |
1136 | 1201 | if (up) | |
1137 | if (line) { | 1202 | uart_resume_port(&serial_txx9_reg, &up->port); |
1138 | pci_enable_device(dev); | ||
1139 | serial_txx9_resume_port(line); | ||
1140 | } | ||
1141 | return 0; | 1203 | return 0; |
1142 | } | 1204 | } |
1143 | #endif | 1205 | #endif |
@@ -1161,6 +1223,8 @@ static struct pci_driver serial_txx9_pci_driver = { | |||
1161 | MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl); | 1223 | MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl); |
1162 | #endif /* ENABLE_SERIAL_TXX9_PCI */ | 1224 | #endif /* ENABLE_SERIAL_TXX9_PCI */ |
1163 | 1225 | ||
1226 | static struct platform_device *serial_txx9_plat_devs; | ||
1227 | |||
1164 | static int __init serial_txx9_init(void) | 1228 | static int __init serial_txx9_init(void) |
1165 | { | 1229 | { |
1166 | int ret; | 1230 | int ret; |
@@ -1168,13 +1232,39 @@ static int __init serial_txx9_init(void) | |||
1168 | printk(KERN_INFO "%s version %s\n", serial_name, serial_version); | 1232 | printk(KERN_INFO "%s version %s\n", serial_name, serial_version); |
1169 | 1233 | ||
1170 | ret = uart_register_driver(&serial_txx9_reg); | 1234 | ret = uart_register_driver(&serial_txx9_reg); |
1171 | if (ret >= 0) { | 1235 | if (ret) |
1172 | serial_txx9_register_ports(&serial_txx9_reg); | 1236 | goto out; |
1237 | |||
1238 | serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1); | ||
1239 | if (!serial_txx9_plat_devs) { | ||
1240 | ret = -ENOMEM; | ||
1241 | goto unreg_uart_drv; | ||
1242 | } | ||
1243 | |||
1244 | ret = platform_device_add(serial_txx9_plat_devs); | ||
1245 | if (ret) | ||
1246 | goto put_dev; | ||
1247 | |||
1248 | serial_txx9_register_ports(&serial_txx9_reg, | ||
1249 | &serial_txx9_plat_devs->dev); | ||
1250 | |||
1251 | ret = platform_driver_register(&serial_txx9_plat_driver); | ||
1252 | if (ret) | ||
1253 | goto del_dev; | ||
1173 | 1254 | ||
1174 | #ifdef ENABLE_SERIAL_TXX9_PCI | 1255 | #ifdef ENABLE_SERIAL_TXX9_PCI |
1175 | ret = pci_register_driver(&serial_txx9_pci_driver); | 1256 | ret = pci_register_driver(&serial_txx9_pci_driver); |
1176 | #endif | 1257 | #endif |
1177 | } | 1258 | if (ret == 0) |
1259 | goto out; | ||
1260 | |||
1261 | del_dev: | ||
1262 | platform_device_del(serial_txx9_plat_devs); | ||
1263 | put_dev: | ||
1264 | platform_device_put(serial_txx9_plat_devs); | ||
1265 | unreg_uart_drv: | ||
1266 | uart_unregister_driver(&serial_txx9_reg); | ||
1267 | out: | ||
1178 | return ret; | 1268 | return ret; |
1179 | } | 1269 | } |
1180 | 1270 | ||
@@ -1185,6 +1275,8 @@ static void __exit serial_txx9_exit(void) | |||
1185 | #ifdef ENABLE_SERIAL_TXX9_PCI | 1275 | #ifdef ENABLE_SERIAL_TXX9_PCI |
1186 | pci_unregister_driver(&serial_txx9_pci_driver); | 1276 | pci_unregister_driver(&serial_txx9_pci_driver); |
1187 | #endif | 1277 | #endif |
1278 | platform_driver_unregister(&serial_txx9_plat_driver); | ||
1279 | platform_device_unregister(serial_txx9_plat_devs); | ||
1188 | for (i = 0; i < UART_NR; i++) { | 1280 | for (i = 0; i < UART_NR; i++) { |
1189 | struct uart_txx9_port *up = &serial_txx9_ports[i]; | 1281 | struct uart_txx9_port *up = &serial_txx9_ports[i]; |
1190 | if (up->port.iobase || up->port.mapbase) | 1282 | if (up->port.iobase || up->port.mapbase) |