diff options
Diffstat (limited to 'drivers/serial/sh-sci.c')
-rw-r--r-- | drivers/serial/sh-sci.c | 388 |
1 files changed, 213 insertions, 175 deletions
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index dbf5357a77b3..a4cf1079b312 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c | |||
@@ -47,12 +47,17 @@ | |||
47 | #include <linux/clk.h> | 47 | #include <linux/clk.h> |
48 | #include <linux/ctype.h> | 48 | #include <linux/ctype.h> |
49 | #include <linux/err.h> | 49 | #include <linux/err.h> |
50 | #include <linux/list.h> | ||
50 | 51 | ||
51 | #ifdef CONFIG_SUPERH | 52 | #ifdef CONFIG_SUPERH |
52 | #include <asm/clock.h> | 53 | #include <asm/clock.h> |
53 | #include <asm/sh_bios.h> | 54 | #include <asm/sh_bios.h> |
54 | #endif | 55 | #endif |
55 | 56 | ||
57 | #ifdef CONFIG_H8300 | ||
58 | #include <asm/gpio.h> | ||
59 | #endif | ||
60 | |||
56 | #include "sh-sci.h" | 61 | #include "sh-sci.h" |
57 | 62 | ||
58 | struct sci_port { | 63 | struct sci_port { |
@@ -75,14 +80,22 @@ struct sci_port { | |||
75 | int break_flag; | 80 | int break_flag; |
76 | 81 | ||
77 | #ifdef CONFIG_HAVE_CLK | 82 | #ifdef CONFIG_HAVE_CLK |
78 | /* Port clock */ | 83 | /* Interface clock */ |
79 | struct clk *clk; | 84 | struct clk *iclk; |
85 | /* Data clock */ | ||
86 | struct clk *dclk; | ||
80 | #endif | 87 | #endif |
88 | struct list_head node; | ||
81 | }; | 89 | }; |
82 | 90 | ||
83 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE | 91 | struct sh_sci_priv { |
84 | static struct sci_port *serial_console_port; | 92 | spinlock_t lock; |
93 | struct list_head ports; | ||
94 | |||
95 | #ifdef CONFIG_HAVE_CLK | ||
96 | struct notifier_block clk_nb; | ||
85 | #endif | 97 | #endif |
98 | }; | ||
86 | 99 | ||
87 | /* Function prototypes */ | 100 | /* Function prototypes */ |
88 | static void sci_stop_tx(struct uart_port *port); | 101 | static void sci_stop_tx(struct uart_port *port); |
@@ -138,9 +151,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) | |||
138 | status = sci_in(port, SCxSR); | 151 | status = sci_in(port, SCxSR); |
139 | } while (!(status & SCxSR_TDxE(port))); | 152 | } while (!(status & SCxSR_TDxE(port))); |
140 | 153 | ||
141 | sci_in(port, SCxSR); /* Dummy read */ | ||
142 | sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); | ||
143 | sci_out(port, SCxTDR, c); | 154 | sci_out(port, SCxTDR, c); |
155 | sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); | ||
144 | } | 156 | } |
145 | #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ | 157 | #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ |
146 | 158 | ||
@@ -159,12 +171,12 @@ static void h8300_sci_config(struct uart_port *port, unsigned int ctrl) | |||
159 | *mstpcrl &= ~mask; | 171 | *mstpcrl &= ~mask; |
160 | } | 172 | } |
161 | 173 | ||
162 | static inline void h8300_sci_enable(struct uart_port *port) | 174 | static void h8300_sci_enable(struct uart_port *port) |
163 | { | 175 | { |
164 | h8300_sci_config(port, sci_enable); | 176 | h8300_sci_config(port, sci_enable); |
165 | } | 177 | } |
166 | 178 | ||
167 | static inline void h8300_sci_disable(struct uart_port *port) | 179 | static void h8300_sci_disable(struct uart_port *port) |
168 | { | 180 | { |
169 | h8300_sci_config(port, sci_disable); | 181 | h8300_sci_config(port, sci_disable); |
170 | } | 182 | } |
@@ -611,7 +623,7 @@ static inline int sci_handle_breaks(struct uart_port *port) | |||
611 | int copied = 0; | 623 | int copied = 0; |
612 | unsigned short status = sci_in(port, SCxSR); | 624 | unsigned short status = sci_in(port, SCxSR); |
613 | struct tty_struct *tty = port->info->port.tty; | 625 | struct tty_struct *tty = port->info->port.tty; |
614 | struct sci_port *s = &sci_ports[port->line]; | 626 | struct sci_port *s = to_sci_port(port); |
615 | 627 | ||
616 | if (uart_handle_break(port)) | 628 | if (uart_handle_break(port)) |
617 | return 0; | 629 | return 0; |
@@ -726,19 +738,43 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) | |||
726 | static int sci_notifier(struct notifier_block *self, | 738 | static int sci_notifier(struct notifier_block *self, |
727 | unsigned long phase, void *p) | 739 | unsigned long phase, void *p) |
728 | { | 740 | { |
729 | int i; | 741 | struct sh_sci_priv *priv = container_of(self, |
742 | struct sh_sci_priv, clk_nb); | ||
743 | struct sci_port *sci_port; | ||
744 | unsigned long flags; | ||
730 | 745 | ||
731 | if ((phase == CPUFREQ_POSTCHANGE) || | 746 | if ((phase == CPUFREQ_POSTCHANGE) || |
732 | (phase == CPUFREQ_RESUMECHANGE)) | 747 | (phase == CPUFREQ_RESUMECHANGE)) { |
733 | for (i = 0; i < SCI_NPORTS; i++) { | 748 | spin_lock_irqsave(&priv->lock, flags); |
734 | struct sci_port *s = &sci_ports[i]; | 749 | list_for_each_entry(sci_port, &priv->ports, node) |
735 | s->port.uartclk = clk_get_rate(s->clk); | 750 | sci_port->port.uartclk = clk_get_rate(sci_port->dclk); |
736 | } | 751 | |
752 | spin_unlock_irqrestore(&priv->lock, flags); | ||
753 | } | ||
737 | 754 | ||
738 | return NOTIFY_OK; | 755 | return NOTIFY_OK; |
739 | } | 756 | } |
740 | 757 | ||
741 | static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; | 758 | static void sci_clk_enable(struct uart_port *port) |
759 | { | ||
760 | struct sci_port *sci_port = to_sci_port(port); | ||
761 | |||
762 | clk_enable(sci_port->dclk); | ||
763 | sci_port->port.uartclk = clk_get_rate(sci_port->dclk); | ||
764 | |||
765 | if (sci_port->iclk) | ||
766 | clk_enable(sci_port->iclk); | ||
767 | } | ||
768 | |||
769 | static void sci_clk_disable(struct uart_port *port) | ||
770 | { | ||
771 | struct sci_port *sci_port = to_sci_port(port); | ||
772 | |||
773 | if (sci_port->iclk) | ||
774 | clk_disable(sci_port->iclk); | ||
775 | |||
776 | clk_disable(sci_port->dclk); | ||
777 | } | ||
742 | #endif | 778 | #endif |
743 | 779 | ||
744 | static int sci_request_irq(struct sci_port *port) | 780 | static int sci_request_irq(struct sci_port *port) |
@@ -865,15 +901,11 @@ static void sci_break_ctl(struct uart_port *port, int break_state) | |||
865 | 901 | ||
866 | static int sci_startup(struct uart_port *port) | 902 | static int sci_startup(struct uart_port *port) |
867 | { | 903 | { |
868 | struct sci_port *s = &sci_ports[port->line]; | 904 | struct sci_port *s = to_sci_port(port); |
869 | 905 | ||
870 | if (s->enable) | 906 | if (s->enable) |
871 | s->enable(port); | 907 | s->enable(port); |
872 | 908 | ||
873 | #ifdef CONFIG_HAVE_CLK | ||
874 | s->clk = clk_get(NULL, "module_clk"); | ||
875 | #endif | ||
876 | |||
877 | sci_request_irq(s); | 909 | sci_request_irq(s); |
878 | sci_start_tx(port); | 910 | sci_start_tx(port); |
879 | sci_start_rx(port, 1); | 911 | sci_start_rx(port, 1); |
@@ -883,7 +915,7 @@ static int sci_startup(struct uart_port *port) | |||
883 | 915 | ||
884 | static void sci_shutdown(struct uart_port *port) | 916 | static void sci_shutdown(struct uart_port *port) |
885 | { | 917 | { |
886 | struct sci_port *s = &sci_ports[port->line]; | 918 | struct sci_port *s = to_sci_port(port); |
887 | 919 | ||
888 | sci_stop_rx(port); | 920 | sci_stop_rx(port); |
889 | sci_stop_tx(port); | 921 | sci_stop_tx(port); |
@@ -891,11 +923,6 @@ static void sci_shutdown(struct uart_port *port) | |||
891 | 923 | ||
892 | if (s->disable) | 924 | if (s->disable) |
893 | s->disable(port); | 925 | s->disable(port); |
894 | |||
895 | #ifdef CONFIG_HAVE_CLK | ||
896 | clk_put(s->clk); | ||
897 | s->clk = NULL; | ||
898 | #endif | ||
899 | } | 926 | } |
900 | 927 | ||
901 | static void sci_set_termios(struct uart_port *port, struct ktermios *termios, | 928 | static void sci_set_termios(struct uart_port *port, struct ktermios *termios, |
@@ -980,25 +1007,31 @@ static int sci_request_port(struct uart_port *port) | |||
980 | 1007 | ||
981 | static void sci_config_port(struct uart_port *port, int flags) | 1008 | static void sci_config_port(struct uart_port *port, int flags) |
982 | { | 1009 | { |
983 | struct sci_port *s = &sci_ports[port->line]; | 1010 | struct sci_port *s = to_sci_port(port); |
984 | 1011 | ||
985 | port->type = s->type; | 1012 | port->type = s->type; |
986 | 1013 | ||
987 | if (port->flags & UPF_IOREMAP && !port->membase) { | 1014 | if (port->membase) |
988 | #if defined(CONFIG_SUPERH64) | 1015 | return; |
989 | port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF"); | 1016 | |
990 | port->membase = (void __iomem *)port->mapbase; | 1017 | if (port->flags & UPF_IOREMAP) { |
991 | #else | ||
992 | port->membase = ioremap_nocache(port->mapbase, 0x40); | 1018 | port->membase = ioremap_nocache(port->mapbase, 0x40); |
993 | #endif | ||
994 | 1019 | ||
995 | dev_err(port->dev, "can't remap port#%d\n", port->line); | 1020 | if (IS_ERR(port->membase)) |
1021 | dev_err(port->dev, "can't remap port#%d\n", port->line); | ||
1022 | } else { | ||
1023 | /* | ||
1024 | * For the simple (and majority of) cases where we don't | ||
1025 | * need to do any remapping, just cast the cookie | ||
1026 | * directly. | ||
1027 | */ | ||
1028 | port->membase = (void __iomem *)port->mapbase; | ||
996 | } | 1029 | } |
997 | } | 1030 | } |
998 | 1031 | ||
999 | static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) | 1032 | static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) |
1000 | { | 1033 | { |
1001 | struct sci_port *s = &sci_ports[port->line]; | 1034 | struct sci_port *s = to_sci_port(port); |
1002 | 1035 | ||
1003 | if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) | 1036 | if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) |
1004 | return -EINVAL; | 1037 | return -EINVAL; |
@@ -1032,63 +1065,60 @@ static struct uart_ops sci_uart_ops = { | |||
1032 | #endif | 1065 | #endif |
1033 | }; | 1066 | }; |
1034 | 1067 | ||
1035 | static void __init sci_init_ports(void) | 1068 | static void __devinit sci_init_single(struct platform_device *dev, |
1069 | struct sci_port *sci_port, | ||
1070 | unsigned int index, | ||
1071 | struct plat_sci_port *p) | ||
1036 | { | 1072 | { |
1037 | static int first = 1; | 1073 | sci_port->port.ops = &sci_uart_ops; |
1038 | int i; | 1074 | sci_port->port.iotype = UPIO_MEM; |
1039 | 1075 | sci_port->port.line = index; | |
1040 | if (!first) | 1076 | sci_port->port.fifosize = 1; |
1041 | return; | ||
1042 | |||
1043 | first = 0; | ||
1044 | |||
1045 | for (i = 0; i < SCI_NPORTS; i++) { | ||
1046 | sci_ports[i].port.ops = &sci_uart_ops; | ||
1047 | sci_ports[i].port.iotype = UPIO_MEM; | ||
1048 | sci_ports[i].port.line = i; | ||
1049 | sci_ports[i].port.fifosize = 1; | ||
1050 | 1077 | ||
1051 | #if defined(__H8300H__) || defined(__H8300S__) | 1078 | #if defined(__H8300H__) || defined(__H8300S__) |
1052 | #ifdef __H8300S__ | 1079 | #ifdef __H8300S__ |
1053 | sci_ports[i].enable = h8300_sci_enable; | 1080 | sci_port->enable = h8300_sci_enable; |
1054 | sci_ports[i].disable = h8300_sci_disable; | 1081 | sci_port->disable = h8300_sci_disable; |
1055 | #endif | 1082 | #endif |
1056 | sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK; | 1083 | sci_port->port.uartclk = CONFIG_CPU_CLOCK; |
1057 | #elif defined(CONFIG_HAVE_CLK) | 1084 | #elif defined(CONFIG_HAVE_CLK) |
1058 | /* | 1085 | sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL; |
1059 | * XXX: We should use a proper SCI/SCIF clock | 1086 | sci_port->dclk = clk_get(&dev->dev, "peripheral_clk"); |
1060 | */ | 1087 | sci_port->enable = sci_clk_enable; |
1061 | { | 1088 | sci_port->disable = sci_clk_disable; |
1062 | struct clk *clk = clk_get(NULL, "module_clk"); | ||
1063 | sci_ports[i].port.uartclk = clk_get_rate(clk); | ||
1064 | clk_put(clk); | ||
1065 | } | ||
1066 | #else | 1089 | #else |
1067 | #error "Need a valid uartclk" | 1090 | #error "Need a valid uartclk" |
1068 | #endif | 1091 | #endif |
1069 | 1092 | ||
1070 | sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i]; | 1093 | sci_port->break_timer.data = (unsigned long)sci_port; |
1071 | sci_ports[i].break_timer.function = sci_break_timer; | 1094 | sci_port->break_timer.function = sci_break_timer; |
1095 | init_timer(&sci_port->break_timer); | ||
1072 | 1096 | ||
1073 | init_timer(&sci_ports[i].break_timer); | 1097 | sci_port->port.mapbase = p->mapbase; |
1074 | } | 1098 | sci_port->port.membase = p->membase; |
1075 | } | ||
1076 | |||
1077 | int __init early_sci_setup(struct uart_port *port) | ||
1078 | { | ||
1079 | if (unlikely(port->line > SCI_NPORTS)) | ||
1080 | return -ENODEV; | ||
1081 | 1099 | ||
1082 | sci_init_ports(); | 1100 | sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; |
1101 | sci_port->port.flags = p->flags; | ||
1102 | sci_port->port.dev = &dev->dev; | ||
1103 | sci_port->type = sci_port->port.type = p->type; | ||
1083 | 1104 | ||
1084 | sci_ports[port->line].port.membase = port->membase; | 1105 | memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); |
1085 | sci_ports[port->line].port.mapbase = port->mapbase; | ||
1086 | sci_ports[port->line].port.type = port->type; | ||
1087 | 1106 | ||
1088 | return 0; | ||
1089 | } | 1107 | } |
1090 | 1108 | ||
1091 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE | 1109 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE |
1110 | static struct tty_driver *serial_console_device(struct console *co, int *index) | ||
1111 | { | ||
1112 | struct uart_driver *p = &sci_uart_driver; | ||
1113 | *index = co->index; | ||
1114 | return p->tty_driver; | ||
1115 | } | ||
1116 | |||
1117 | static void serial_console_putchar(struct uart_port *port, int ch) | ||
1118 | { | ||
1119 | sci_poll_put_char(port, ch); | ||
1120 | } | ||
1121 | |||
1092 | /* | 1122 | /* |
1093 | * Print a string to the serial port trying not to disturb | 1123 | * Print a string to the serial port trying not to disturb |
1094 | * any possible real use of the port... | 1124 | * any possible real use of the port... |
@@ -1096,25 +1126,27 @@ int __init early_sci_setup(struct uart_port *port) | |||
1096 | static void serial_console_write(struct console *co, const char *s, | 1126 | static void serial_console_write(struct console *co, const char *s, |
1097 | unsigned count) | 1127 | unsigned count) |
1098 | { | 1128 | { |
1099 | struct uart_port *port = &serial_console_port->port; | 1129 | struct uart_port *port = co->data; |
1130 | struct sci_port *sci_port = to_sci_port(port); | ||
1100 | unsigned short bits; | 1131 | unsigned short bits; |
1101 | int i; | ||
1102 | 1132 | ||
1103 | for (i = 0; i < count; i++) { | 1133 | if (sci_port->enable) |
1104 | if (*s == 10) | 1134 | sci_port->enable(port); |
1105 | sci_poll_put_char(port, '\r'); | ||
1106 | 1135 | ||
1107 | sci_poll_put_char(port, *s++); | 1136 | uart_console_write(port, s, count, serial_console_putchar); |
1108 | } | ||
1109 | 1137 | ||
1110 | /* wait until fifo is empty and last bit has been transmitted */ | 1138 | /* wait until fifo is empty and last bit has been transmitted */ |
1111 | bits = SCxSR_TDxE(port) | SCxSR_TEND(port); | 1139 | bits = SCxSR_TDxE(port) | SCxSR_TEND(port); |
1112 | while ((sci_in(port, SCxSR) & bits) != bits) | 1140 | while ((sci_in(port, SCxSR) & bits) != bits) |
1113 | cpu_relax(); | 1141 | cpu_relax(); |
1142 | |||
1143 | if (sci_port->disable); | ||
1144 | sci_port->disable(port); | ||
1114 | } | 1145 | } |
1115 | 1146 | ||
1116 | static int __init serial_console_setup(struct console *co, char *options) | 1147 | static int __init serial_console_setup(struct console *co, char *options) |
1117 | { | 1148 | { |
1149 | struct sci_port *sci_port; | ||
1118 | struct uart_port *port; | 1150 | struct uart_port *port; |
1119 | int baud = 115200; | 1151 | int baud = 115200; |
1120 | int bits = 8; | 1152 | int bits = 8; |
@@ -1130,8 +1162,9 @@ static int __init serial_console_setup(struct console *co, char *options) | |||
1130 | if (co->index >= SCI_NPORTS) | 1162 | if (co->index >= SCI_NPORTS) |
1131 | co->index = 0; | 1163 | co->index = 0; |
1132 | 1164 | ||
1133 | serial_console_port = &sci_ports[co->index]; | 1165 | sci_port = &sci_ports[co->index]; |
1134 | port = &serial_console_port->port; | 1166 | port = &sci_port->port; |
1167 | co->data = port; | ||
1135 | 1168 | ||
1136 | /* | 1169 | /* |
1137 | * Also need to check port->type, we don't actually have any | 1170 | * Also need to check port->type, we don't actually have any |
@@ -1141,21 +1174,11 @@ static int __init serial_console_setup(struct console *co, char *options) | |||
1141 | */ | 1174 | */ |
1142 | if (!port->type) | 1175 | if (!port->type) |
1143 | return -ENODEV; | 1176 | return -ENODEV; |
1144 | if (!port->membase || !port->mapbase) | ||
1145 | return -ENODEV; | ||
1146 | |||
1147 | port->type = serial_console_port->type; | ||
1148 | |||
1149 | #ifdef CONFIG_HAVE_CLK | ||
1150 | if (!serial_console_port->clk) | ||
1151 | serial_console_port->clk = clk_get(NULL, "module_clk"); | ||
1152 | #endif | ||
1153 | 1177 | ||
1154 | if (port->flags & UPF_IOREMAP) | 1178 | sci_config_port(port, 0); |
1155 | sci_config_port(port, 0); | ||
1156 | 1179 | ||
1157 | if (serial_console_port->enable) | 1180 | if (sci_port->enable) |
1158 | serial_console_port->enable(port); | 1181 | sci_port->enable(port); |
1159 | 1182 | ||
1160 | if (options) | 1183 | if (options) |
1161 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 1184 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
@@ -1166,22 +1189,21 @@ static int __init serial_console_setup(struct console *co, char *options) | |||
1166 | if (ret == 0) | 1189 | if (ret == 0) |
1167 | sci_stop_rx(port); | 1190 | sci_stop_rx(port); |
1168 | #endif | 1191 | #endif |
1192 | /* TODO: disable clock */ | ||
1169 | return ret; | 1193 | return ret; |
1170 | } | 1194 | } |
1171 | 1195 | ||
1172 | static struct console serial_console = { | 1196 | static struct console serial_console = { |
1173 | .name = "ttySC", | 1197 | .name = "ttySC", |
1174 | .device = uart_console_device, | 1198 | .device = serial_console_device, |
1175 | .write = serial_console_write, | 1199 | .write = serial_console_write, |
1176 | .setup = serial_console_setup, | 1200 | .setup = serial_console_setup, |
1177 | .flags = CON_PRINTBUFFER, | 1201 | .flags = CON_PRINTBUFFER, |
1178 | .index = -1, | 1202 | .index = -1, |
1179 | .data = &sci_uart_driver, | ||
1180 | }; | 1203 | }; |
1181 | 1204 | ||
1182 | static int __init sci_console_init(void) | 1205 | static int __init sci_console_init(void) |
1183 | { | 1206 | { |
1184 | sci_init_ports(); | ||
1185 | register_console(&serial_console); | 1207 | register_console(&serial_console); |
1186 | return 0; | 1208 | return 0; |
1187 | } | 1209 | } |
@@ -1207,6 +1229,61 @@ static struct uart_driver sci_uart_driver = { | |||
1207 | .cons = SCI_CONSOLE, | 1229 | .cons = SCI_CONSOLE, |
1208 | }; | 1230 | }; |
1209 | 1231 | ||
1232 | |||
1233 | static int sci_remove(struct platform_device *dev) | ||
1234 | { | ||
1235 | struct sh_sci_priv *priv = platform_get_drvdata(dev); | ||
1236 | struct sci_port *p; | ||
1237 | unsigned long flags; | ||
1238 | |||
1239 | #ifdef CONFIG_HAVE_CLK | ||
1240 | cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1241 | #endif | ||
1242 | |||
1243 | spin_lock_irqsave(&priv->lock, flags); | ||
1244 | list_for_each_entry(p, &priv->ports, node) | ||
1245 | uart_remove_one_port(&sci_uart_driver, &p->port); | ||
1246 | |||
1247 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1248 | |||
1249 | kfree(priv); | ||
1250 | return 0; | ||
1251 | } | ||
1252 | |||
1253 | static int __devinit sci_probe_single(struct platform_device *dev, | ||
1254 | unsigned int index, | ||
1255 | struct plat_sci_port *p, | ||
1256 | struct sci_port *sciport) | ||
1257 | { | ||
1258 | struct sh_sci_priv *priv = platform_get_drvdata(dev); | ||
1259 | unsigned long flags; | ||
1260 | int ret; | ||
1261 | |||
1262 | /* Sanity check */ | ||
1263 | if (unlikely(index >= SCI_NPORTS)) { | ||
1264 | dev_notice(&dev->dev, "Attempting to register port " | ||
1265 | "%d when only %d are available.\n", | ||
1266 | index+1, SCI_NPORTS); | ||
1267 | dev_notice(&dev->dev, "Consider bumping " | ||
1268 | "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); | ||
1269 | return 0; | ||
1270 | } | ||
1271 | |||
1272 | sci_init_single(dev, sciport, index, p); | ||
1273 | |||
1274 | ret = uart_add_one_port(&sci_uart_driver, &sciport->port); | ||
1275 | if (ret) | ||
1276 | return ret; | ||
1277 | |||
1278 | INIT_LIST_HEAD(&sciport->node); | ||
1279 | |||
1280 | spin_lock_irqsave(&priv->lock, flags); | ||
1281 | list_add(&sciport->node, &priv->ports); | ||
1282 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1283 | |||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1210 | /* | 1287 | /* |
1211 | * Register a set of serial devices attached to a platform device. The | 1288 | * Register a set of serial devices attached to a platform device. The |
1212 | * list is terminated with a zero flags entry, which means we expect | 1289 | * list is terminated with a zero flags entry, which means we expect |
@@ -1216,57 +1293,34 @@ static struct uart_driver sci_uart_driver = { | |||
1216 | static int __devinit sci_probe(struct platform_device *dev) | 1293 | static int __devinit sci_probe(struct platform_device *dev) |
1217 | { | 1294 | { |
1218 | struct plat_sci_port *p = dev->dev.platform_data; | 1295 | struct plat_sci_port *p = dev->dev.platform_data; |
1296 | struct sh_sci_priv *priv; | ||
1219 | int i, ret = -EINVAL; | 1297 | int i, ret = -EINVAL; |
1220 | 1298 | ||
1221 | for (i = 0; p && p->flags != 0; p++, i++) { | 1299 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
1222 | struct sci_port *sciport = &sci_ports[i]; | 1300 | if (!priv) |
1301 | return -ENOMEM; | ||
1223 | 1302 | ||
1224 | /* Sanity check */ | 1303 | INIT_LIST_HEAD(&priv->ports); |
1225 | if (unlikely(i == SCI_NPORTS)) { | 1304 | spin_lock_init(&priv->lock); |
1226 | dev_notice(&dev->dev, "Attempting to register port " | 1305 | platform_set_drvdata(dev, priv); |
1227 | "%d when only %d are available.\n", | ||
1228 | i+1, SCI_NPORTS); | ||
1229 | dev_notice(&dev->dev, "Consider bumping " | ||
1230 | "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); | ||
1231 | break; | ||
1232 | } | ||
1233 | 1306 | ||
1234 | sciport->port.mapbase = p->mapbase; | 1307 | #ifdef CONFIG_HAVE_CLK |
1308 | priv->clk_nb.notifier_call = sci_notifier; | ||
1309 | cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1310 | #endif | ||
1235 | 1311 | ||
1236 | if (p->mapbase && !p->membase) { | 1312 | if (dev->id != -1) { |
1237 | if (p->flags & UPF_IOREMAP) { | 1313 | ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]); |
1238 | p->membase = ioremap_nocache(p->mapbase, 0x40); | 1314 | if (ret) |
1239 | if (IS_ERR(p->membase)) { | 1315 | goto err_unreg; |
1240 | ret = PTR_ERR(p->membase); | 1316 | } else { |
1241 | goto err_unreg; | 1317 | for (i = 0; p && p->flags != 0; p++, i++) { |
1242 | } | 1318 | ret = sci_probe_single(dev, i, p, &sci_ports[i]); |
1243 | } else { | 1319 | if (ret) |
1244 | /* | 1320 | goto err_unreg; |
1245 | * For the simple (and majority of) cases | ||
1246 | * where we don't need to do any remapping, | ||
1247 | * just cast the cookie directly. | ||
1248 | */ | ||
1249 | p->membase = (void __iomem *)p->mapbase; | ||
1250 | } | ||
1251 | } | 1321 | } |
1252 | |||
1253 | sciport->port.membase = p->membase; | ||
1254 | |||
1255 | sciport->port.irq = p->irqs[SCIx_TXI_IRQ]; | ||
1256 | sciport->port.flags = p->flags; | ||
1257 | sciport->port.dev = &dev->dev; | ||
1258 | |||
1259 | sciport->type = sciport->port.type = p->type; | ||
1260 | |||
1261 | memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); | ||
1262 | |||
1263 | uart_add_one_port(&sci_uart_driver, &sciport->port); | ||
1264 | } | 1322 | } |
1265 | 1323 | ||
1266 | #ifdef CONFIG_HAVE_CLK | ||
1267 | cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1268 | #endif | ||
1269 | |||
1270 | #ifdef CONFIG_SH_STANDARD_BIOS | 1324 | #ifdef CONFIG_SH_STANDARD_BIOS |
1271 | sh_bios_gdb_detach(); | 1325 | sh_bios_gdb_detach(); |
1272 | #endif | 1326 | #endif |
@@ -1274,50 +1328,36 @@ static int __devinit sci_probe(struct platform_device *dev) | |||
1274 | return 0; | 1328 | return 0; |
1275 | 1329 | ||
1276 | err_unreg: | 1330 | err_unreg: |
1277 | for (i = i - 1; i >= 0; i--) | 1331 | sci_remove(dev); |
1278 | uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); | ||
1279 | |||
1280 | return ret; | 1332 | return ret; |
1281 | } | 1333 | } |
1282 | 1334 | ||
1283 | static int __devexit sci_remove(struct platform_device *dev) | ||
1284 | { | ||
1285 | int i; | ||
1286 | |||
1287 | #ifdef CONFIG_HAVE_CLK | ||
1288 | cpufreq_unregister_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1289 | #endif | ||
1290 | |||
1291 | for (i = 0; i < SCI_NPORTS; i++) | ||
1292 | uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1296 | |||
1297 | static int sci_suspend(struct platform_device *dev, pm_message_t state) | 1335 | static int sci_suspend(struct platform_device *dev, pm_message_t state) |
1298 | { | 1336 | { |
1299 | int i; | 1337 | struct sh_sci_priv *priv = platform_get_drvdata(dev); |
1338 | struct sci_port *p; | ||
1339 | unsigned long flags; | ||
1300 | 1340 | ||
1301 | for (i = 0; i < SCI_NPORTS; i++) { | 1341 | spin_lock_irqsave(&priv->lock, flags); |
1302 | struct sci_port *p = &sci_ports[i]; | 1342 | list_for_each_entry(p, &priv->ports, node) |
1343 | uart_suspend_port(&sci_uart_driver, &p->port); | ||
1303 | 1344 | ||
1304 | if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) | 1345 | spin_unlock_irqrestore(&priv->lock, flags); |
1305 | uart_suspend_port(&sci_uart_driver, &p->port); | ||
1306 | } | ||
1307 | 1346 | ||
1308 | return 0; | 1347 | return 0; |
1309 | } | 1348 | } |
1310 | 1349 | ||
1311 | static int sci_resume(struct platform_device *dev) | 1350 | static int sci_resume(struct platform_device *dev) |
1312 | { | 1351 | { |
1313 | int i; | 1352 | struct sh_sci_priv *priv = platform_get_drvdata(dev); |
1353 | struct sci_port *p; | ||
1354 | unsigned long flags; | ||
1314 | 1355 | ||
1315 | for (i = 0; i < SCI_NPORTS; i++) { | 1356 | spin_lock_irqsave(&priv->lock, flags); |
1316 | struct sci_port *p = &sci_ports[i]; | 1357 | list_for_each_entry(p, &priv->ports, node) |
1358 | uart_resume_port(&sci_uart_driver, &p->port); | ||
1317 | 1359 | ||
1318 | if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) | 1360 | spin_unlock_irqrestore(&priv->lock, flags); |
1319 | uart_resume_port(&sci_uart_driver, &p->port); | ||
1320 | } | ||
1321 | 1361 | ||
1322 | return 0; | 1362 | return 0; |
1323 | } | 1363 | } |
@@ -1339,8 +1379,6 @@ static int __init sci_init(void) | |||
1339 | 1379 | ||
1340 | printk(banner); | 1380 | printk(banner); |
1341 | 1381 | ||
1342 | sci_init_ports(); | ||
1343 | |||
1344 | ret = uart_register_driver(&sci_uart_driver); | 1382 | ret = uart_register_driver(&sci_uart_driver); |
1345 | if (likely(ret == 0)) { | 1383 | if (likely(ret == 0)) { |
1346 | ret = platform_driver_register(&sci_driver); | 1384 | ret = platform_driver_register(&sci_driver); |