diff options
author | Magnus Damm <damm@igel.co.jp> | 2009-01-21 10:14:30 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-05-08 10:22:26 -0400 |
commit | 501b825d01efb93766c87d29f299851152cf4eb0 (patch) | |
tree | e80ece8e1b458aae3f601f1f23dd7b1173b1b366 /drivers/serial/sh-sci.c | |
parent | 08f8cb315fdf9195b472aeb440ae65b189b151da (diff) |
sh-sci: improve clock framework support
Use enable/disable hooks for clock framework integration.
Make sure we control the clock for the serial console as well.
Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/serial/sh-sci.c')
-rw-r--r-- | drivers/serial/sh-sci.c | 77 |
1 files changed, 46 insertions, 31 deletions
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 408624ae7fec..3daf76725ac6 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c | |||
@@ -76,8 +76,10 @@ struct sci_port { | |||
76 | int break_flag; | 76 | int break_flag; |
77 | 77 | ||
78 | #ifdef CONFIG_HAVE_CLK | 78 | #ifdef CONFIG_HAVE_CLK |
79 | /* Port clock */ | 79 | /* Interface clock */ |
80 | struct clk *clk; | 80 | struct clk *iclk; |
81 | /* Data clock */ | ||
82 | struct clk *dclk; | ||
81 | #endif | 83 | #endif |
82 | struct list_head node; | 84 | struct list_head node; |
83 | }; | 85 | }; |
@@ -166,12 +168,12 @@ static void h8300_sci_config(struct uart_port *port, unsigned int ctrl) | |||
166 | *mstpcrl &= ~mask; | 168 | *mstpcrl &= ~mask; |
167 | } | 169 | } |
168 | 170 | ||
169 | static inline void h8300_sci_enable(struct uart_port *port) | 171 | static void h8300_sci_enable(struct uart_port *port) |
170 | { | 172 | { |
171 | h8300_sci_config(port, sci_enable); | 173 | h8300_sci_config(port, sci_enable); |
172 | } | 174 | } |
173 | 175 | ||
174 | static inline void h8300_sci_disable(struct uart_port *port) | 176 | static void h8300_sci_disable(struct uart_port *port) |
175 | { | 177 | { |
176 | h8300_sci_config(port, sci_disable); | 178 | h8300_sci_config(port, sci_disable); |
177 | } | 179 | } |
@@ -742,13 +744,34 @@ static int sci_notifier(struct notifier_block *self, | |||
742 | (phase == CPUFREQ_RESUMECHANGE)) { | 744 | (phase == CPUFREQ_RESUMECHANGE)) { |
743 | spin_lock_irqsave(&priv->lock, flags); | 745 | spin_lock_irqsave(&priv->lock, flags); |
744 | list_for_each_entry(sci_port, &priv->ports, node) | 746 | list_for_each_entry(sci_port, &priv->ports, node) |
745 | sci_port->port.uartclk = clk_get_rate(sci_port->clk); | 747 | sci_port->port.uartclk = clk_get_rate(sci_port->dclk); |
746 | 748 | ||
747 | spin_unlock_irqrestore(&priv->lock, flags); | 749 | spin_unlock_irqrestore(&priv->lock, flags); |
748 | } | 750 | } |
749 | 751 | ||
750 | return NOTIFY_OK; | 752 | return NOTIFY_OK; |
751 | } | 753 | } |
754 | |||
755 | static void sci_clk_enable(struct uart_port *port) | ||
756 | { | ||
757 | struct sci_port *sci_port = to_sci_port(port); | ||
758 | |||
759 | clk_enable(sci_port->dclk); | ||
760 | sci_port->port.uartclk = clk_get_rate(sci_port->dclk); | ||
761 | |||
762 | if (sci_port->iclk) | ||
763 | clk_enable(sci_port->iclk); | ||
764 | } | ||
765 | |||
766 | static void sci_clk_disable(struct uart_port *port) | ||
767 | { | ||
768 | struct sci_port *sci_port = to_sci_port(port); | ||
769 | |||
770 | if (sci_port->iclk) | ||
771 | clk_disable(sci_port->iclk); | ||
772 | |||
773 | clk_disable(sci_port->dclk); | ||
774 | } | ||
752 | #endif | 775 | #endif |
753 | 776 | ||
754 | static int sci_request_irq(struct sci_port *port) | 777 | static int sci_request_irq(struct sci_port *port) |
@@ -880,10 +903,6 @@ static int sci_startup(struct uart_port *port) | |||
880 | if (s->enable) | 903 | if (s->enable) |
881 | s->enable(port); | 904 | s->enable(port); |
882 | 905 | ||
883 | #ifdef CONFIG_HAVE_CLK | ||
884 | s->clk = clk_get(NULL, "module_clk"); | ||
885 | #endif | ||
886 | |||
887 | sci_request_irq(s); | 906 | sci_request_irq(s); |
888 | sci_start_tx(port); | 907 | sci_start_tx(port); |
889 | sci_start_rx(port, 1); | 908 | sci_start_rx(port, 1); |
@@ -901,11 +920,6 @@ static void sci_shutdown(struct uart_port *port) | |||
901 | 920 | ||
902 | if (s->disable) | 921 | if (s->disable) |
903 | s->disable(port); | 922 | s->disable(port); |
904 | |||
905 | #ifdef CONFIG_HAVE_CLK | ||
906 | clk_put(s->clk); | ||
907 | s->clk = NULL; | ||
908 | #endif | ||
909 | } | 923 | } |
910 | 924 | ||
911 | static void sci_set_termios(struct uart_port *port, struct ktermios *termios, | 925 | static void sci_set_termios(struct uart_port *port, struct ktermios *termios, |
@@ -1048,7 +1062,8 @@ static struct uart_ops sci_uart_ops = { | |||
1048 | #endif | 1062 | #endif |
1049 | }; | 1063 | }; |
1050 | 1064 | ||
1051 | static void __devinit sci_init_single(struct sci_port *sci_port, | 1065 | static void __devinit sci_init_single(struct platform_device *dev, |
1066 | struct sci_port *sci_port, | ||
1052 | unsigned int index, | 1067 | unsigned int index, |
1053 | struct plat_sci_port *p) | 1068 | struct plat_sci_port *p) |
1054 | { | 1069 | { |
@@ -1064,14 +1079,10 @@ static void __devinit sci_init_single(struct sci_port *sci_port, | |||
1064 | #endif | 1079 | #endif |
1065 | sci_port->port.uartclk = CONFIG_CPU_CLOCK; | 1080 | sci_port->port.uartclk = CONFIG_CPU_CLOCK; |
1066 | #elif defined(CONFIG_HAVE_CLK) | 1081 | #elif defined(CONFIG_HAVE_CLK) |
1067 | /* | 1082 | sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL; |
1068 | * XXX: We should use a proper SCI/SCIF clock | 1083 | sci_port->dclk = clk_get(&dev->dev, "module_clk"); |
1069 | */ | 1084 | sci_port->enable = sci_clk_enable; |
1070 | { | 1085 | sci_port->disable = sci_clk_disable; |
1071 | struct clk *clk = clk_get(NULL, "module_clk"); | ||
1072 | sci_port->port.uartclk = clk_get_rate(clk); | ||
1073 | clk_put(clk); | ||
1074 | } | ||
1075 | #else | 1086 | #else |
1076 | #error "Need a valid uartclk" | 1087 | #error "Need a valid uartclk" |
1077 | #endif | 1088 | #endif |
@@ -1085,9 +1096,11 @@ static void __devinit sci_init_single(struct sci_port *sci_port, | |||
1085 | 1096 | ||
1086 | sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; | 1097 | sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; |
1087 | sci_port->port.flags = p->flags; | 1098 | sci_port->port.flags = p->flags; |
1099 | sci_port->port.dev = &dev->dev; | ||
1088 | sci_port->type = sci_port->port.type = p->type; | 1100 | sci_port->type = sci_port->port.type = p->type; |
1089 | 1101 | ||
1090 | memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); | 1102 | memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); |
1103 | |||
1091 | } | 1104 | } |
1092 | 1105 | ||
1093 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE | 1106 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE |
@@ -1111,14 +1124,21 @@ static void serial_console_write(struct console *co, const char *s, | |||
1111 | unsigned count) | 1124 | unsigned count) |
1112 | { | 1125 | { |
1113 | struct uart_port *port = co->data; | 1126 | struct uart_port *port = co->data; |
1127 | struct sci_port *sci_port = to_sci_port(port); | ||
1114 | unsigned short bits; | 1128 | unsigned short bits; |
1115 | 1129 | ||
1116 | uart_console_write(co->data, s, count, serial_console_putchar); | 1130 | if (sci_port->enable) |
1131 | sci_port->enable(port); | ||
1132 | |||
1133 | uart_console_write(port, s, count, serial_console_putchar); | ||
1117 | 1134 | ||
1118 | /* wait until fifo is empty and last bit has been transmitted */ | 1135 | /* wait until fifo is empty and last bit has been transmitted */ |
1119 | bits = SCxSR_TDxE(port) | SCxSR_TEND(port); | 1136 | bits = SCxSR_TDxE(port) | SCxSR_TEND(port); |
1120 | while ((sci_in(port, SCxSR) & bits) != bits) | 1137 | while ((sci_in(port, SCxSR) & bits) != bits) |
1121 | cpu_relax(); | 1138 | cpu_relax(); |
1139 | |||
1140 | if (sci_port->disable); | ||
1141 | sci_port->disable(port); | ||
1122 | } | 1142 | } |
1123 | 1143 | ||
1124 | static int __init serial_console_setup(struct console *co, char *options) | 1144 | static int __init serial_console_setup(struct console *co, char *options) |
@@ -1152,11 +1172,6 @@ static int __init serial_console_setup(struct console *co, char *options) | |||
1152 | if (!port->type) | 1172 | if (!port->type) |
1153 | return -ENODEV; | 1173 | return -ENODEV; |
1154 | 1174 | ||
1155 | #ifdef CONFIG_HAVE_CLK | ||
1156 | if (!sci_port->clk) | ||
1157 | sci_port->clk = clk_get(NULL, "module_clk"); | ||
1158 | #endif | ||
1159 | |||
1160 | sci_config_port(port, 0); | 1175 | sci_config_port(port, 0); |
1161 | 1176 | ||
1162 | if (sci_port->enable) | 1177 | if (sci_port->enable) |
@@ -1171,6 +1186,7 @@ static int __init serial_console_setup(struct console *co, char *options) | |||
1171 | if (ret == 0) | 1186 | if (ret == 0) |
1172 | sci_stop_rx(port); | 1187 | sci_stop_rx(port); |
1173 | #endif | 1188 | #endif |
1189 | /* TODO: disable clock */ | ||
1174 | return ret; | 1190 | return ret; |
1175 | } | 1191 | } |
1176 | 1192 | ||
@@ -1250,8 +1266,7 @@ static int __devinit sci_probe_single(struct platform_device *dev, | |||
1250 | return 0; | 1266 | return 0; |
1251 | } | 1267 | } |
1252 | 1268 | ||
1253 | sciport->port.dev = &dev->dev; | 1269 | sci_init_single(dev, sciport, index, p); |
1254 | sci_init_single(sciport, index, p); | ||
1255 | 1270 | ||
1256 | ret = uart_add_one_port(&sci_uart_driver, &sciport->port); | 1271 | ret = uart_add_one_port(&sci_uart_driver, &sciport->port); |
1257 | if (ret) | 1272 | if (ret) |