diff options
author | Magnus Damm <damm@igel.co.jp> | 2009-01-21 10:13:42 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-05-08 09:50:47 -0400 |
commit | e552de2413edad1a7b0c7f82a2f2753e4f905d93 (patch) | |
tree | 45ecd6a536d17318c9b9f279a81d9cbe2a7bd17d /drivers/serial/sh-sci.c | |
parent | 7b551f9daa9bd9533ba4ce31622ed4be1dd97d3e (diff) |
sh-sci: add platform device private data
This patch adds per-platform private data to the sh-sci driver.
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 | 127 |
1 files changed, 85 insertions, 42 deletions
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 728d6a062bf6..af5da110d52b 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c | |||
@@ -47,6 +47,7 @@ | |||
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> |
@@ -78,6 +79,16 @@ struct sci_port { | |||
78 | /* Port clock */ | 79 | /* Port clock */ |
79 | struct clk *clk; | 80 | struct clk *clk; |
80 | #endif | 81 | #endif |
82 | struct list_head node; | ||
83 | }; | ||
84 | |||
85 | struct sh_sci_priv { | ||
86 | spinlock_t lock; | ||
87 | struct list_head ports; | ||
88 | |||
89 | #ifdef CONFIG_HAVE_CLK | ||
90 | struct notifier_block clk_nb; | ||
91 | #endif | ||
81 | }; | 92 | }; |
82 | 93 | ||
83 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE | 94 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE |
@@ -726,19 +737,22 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) | |||
726 | static int sci_notifier(struct notifier_block *self, | 737 | static int sci_notifier(struct notifier_block *self, |
727 | unsigned long phase, void *p) | 738 | unsigned long phase, void *p) |
728 | { | 739 | { |
729 | int i; | 740 | struct sh_sci_priv *priv = container_of(self, |
741 | struct sh_sci_priv, clk_nb); | ||
742 | struct sci_port *sci_port; | ||
743 | unsigned long flags; | ||
730 | 744 | ||
731 | if ((phase == CPUFREQ_POSTCHANGE) || | 745 | if ((phase == CPUFREQ_POSTCHANGE) || |
732 | (phase == CPUFREQ_RESUMECHANGE)) | 746 | (phase == CPUFREQ_RESUMECHANGE)) { |
733 | for (i = 0; i < SCI_NPORTS; i++) { | 747 | spin_lock_irqsave(&priv->lock, flags); |
734 | struct sci_port *s = &sci_ports[i]; | 748 | list_for_each_entry(sci_port, &priv->ports, node) |
735 | s->port.uartclk = clk_get_rate(s->clk); | 749 | sci_port->port.uartclk = clk_get_rate(sci_port->clk); |
736 | } | 750 | |
751 | spin_unlock_irqrestore(&priv->lock, flags); | ||
752 | } | ||
737 | 753 | ||
738 | return NOTIFY_OK; | 754 | return NOTIFY_OK; |
739 | } | 755 | } |
740 | |||
741 | static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; | ||
742 | #endif | 756 | #endif |
743 | 757 | ||
744 | static int sci_request_irq(struct sci_port *port) | 758 | static int sci_request_irq(struct sci_port *port) |
@@ -1201,6 +1215,27 @@ static struct uart_driver sci_uart_driver = { | |||
1201 | .cons = SCI_CONSOLE, | 1215 | .cons = SCI_CONSOLE, |
1202 | }; | 1216 | }; |
1203 | 1217 | ||
1218 | |||
1219 | static int __devexit sci_remove(struct platform_device *dev) | ||
1220 | { | ||
1221 | struct sh_sci_priv *priv = platform_get_drvdata(dev); | ||
1222 | struct sci_port *p; | ||
1223 | unsigned long flags; | ||
1224 | |||
1225 | #ifdef CONFIG_HAVE_CLK | ||
1226 | cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1227 | #endif | ||
1228 | |||
1229 | spin_lock_irqsave(&priv->lock, flags); | ||
1230 | list_for_each_entry(p, &priv->ports, node) | ||
1231 | uart_remove_one_port(&sci_uart_driver, &p->port); | ||
1232 | |||
1233 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1234 | |||
1235 | kfree(priv); | ||
1236 | return 0; | ||
1237 | } | ||
1238 | |||
1204 | /* | 1239 | /* |
1205 | * Register a set of serial devices attached to a platform device. The | 1240 | * Register a set of serial devices attached to a platform device. The |
1206 | * list is terminated with a zero flags entry, which means we expect | 1241 | * list is terminated with a zero flags entry, which means we expect |
@@ -1210,7 +1245,22 @@ static struct uart_driver sci_uart_driver = { | |||
1210 | static int __devinit sci_probe(struct platform_device *dev) | 1245 | static int __devinit sci_probe(struct platform_device *dev) |
1211 | { | 1246 | { |
1212 | struct plat_sci_port *p = dev->dev.platform_data; | 1247 | struct plat_sci_port *p = dev->dev.platform_data; |
1248 | struct sh_sci_priv *priv; | ||
1213 | int i, ret = -EINVAL; | 1249 | int i, ret = -EINVAL; |
1250 | unsigned long flags; | ||
1251 | |||
1252 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
1253 | if (!priv) | ||
1254 | return -ENOMEM; | ||
1255 | |||
1256 | INIT_LIST_HEAD(&priv->ports); | ||
1257 | spin_lock_init(&priv->lock); | ||
1258 | platform_set_drvdata(dev, priv); | ||
1259 | |||
1260 | #ifdef CONFIG_HAVE_CLK | ||
1261 | priv->clk_nb.notifier_call = sci_notifier; | ||
1262 | cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1263 | #endif | ||
1214 | 1264 | ||
1215 | for (i = 0; p && p->flags != 0; p++, i++) { | 1265 | for (i = 0; p && p->flags != 0; p++, i++) { |
1216 | struct sci_port *sciport = &sci_ports[i]; | 1266 | struct sci_port *sciport = &sci_ports[i]; |
@@ -1254,12 +1304,19 @@ static int __devinit sci_probe(struct platform_device *dev) | |||
1254 | 1304 | ||
1255 | memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); | 1305 | memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); |
1256 | 1306 | ||
1257 | uart_add_one_port(&sci_uart_driver, &sciport->port); | 1307 | ret = uart_add_one_port(&sci_uart_driver, &sciport->port); |
1258 | } | ||
1259 | 1308 | ||
1260 | #ifdef CONFIG_HAVE_CLK | 1309 | if (ret && (p->flags & UPF_IOREMAP)) { |
1261 | cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); | 1310 | iounmap(p->membase); |
1262 | #endif | 1311 | goto err_unreg; |
1312 | } | ||
1313 | |||
1314 | INIT_LIST_HEAD(&sciport->node); | ||
1315 | |||
1316 | spin_lock_irqsave(&priv->lock, flags); | ||
1317 | list_add(&sciport->node, &priv->ports); | ||
1318 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1319 | } | ||
1263 | 1320 | ||
1264 | #ifdef CONFIG_SH_STANDARD_BIOS | 1321 | #ifdef CONFIG_SH_STANDARD_BIOS |
1265 | sh_bios_gdb_detach(); | 1322 | sh_bios_gdb_detach(); |
@@ -1268,50 +1325,36 @@ static int __devinit sci_probe(struct platform_device *dev) | |||
1268 | return 0; | 1325 | return 0; |
1269 | 1326 | ||
1270 | err_unreg: | 1327 | err_unreg: |
1271 | for (i = i - 1; i >= 0; i--) | 1328 | sci_remove(dev); |
1272 | uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); | ||
1273 | |||
1274 | return ret; | 1329 | return ret; |
1275 | } | 1330 | } |
1276 | 1331 | ||
1277 | static int __devexit sci_remove(struct platform_device *dev) | ||
1278 | { | ||
1279 | int i; | ||
1280 | |||
1281 | #ifdef CONFIG_HAVE_CLK | ||
1282 | cpufreq_unregister_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1283 | #endif | ||
1284 | |||
1285 | for (i = 0; i < SCI_NPORTS; i++) | ||
1286 | uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); | ||
1287 | |||
1288 | return 0; | ||
1289 | } | ||
1290 | |||
1291 | static int sci_suspend(struct platform_device *dev, pm_message_t state) | 1332 | static int sci_suspend(struct platform_device *dev, pm_message_t state) |
1292 | { | 1333 | { |
1293 | int i; | 1334 | struct sh_sci_priv *priv = platform_get_drvdata(dev); |
1335 | struct sci_port *p; | ||
1336 | unsigned long flags; | ||
1294 | 1337 | ||
1295 | for (i = 0; i < SCI_NPORTS; i++) { | 1338 | spin_lock_irqsave(&priv->lock, flags); |
1296 | struct sci_port *p = &sci_ports[i]; | 1339 | list_for_each_entry(p, &priv->ports, node) |
1340 | uart_suspend_port(&sci_uart_driver, &p->port); | ||
1297 | 1341 | ||
1298 | if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) | 1342 | spin_unlock_irqrestore(&priv->lock, flags); |
1299 | uart_suspend_port(&sci_uart_driver, &p->port); | ||
1300 | } | ||
1301 | 1343 | ||
1302 | return 0; | 1344 | return 0; |
1303 | } | 1345 | } |
1304 | 1346 | ||
1305 | static int sci_resume(struct platform_device *dev) | 1347 | static int sci_resume(struct platform_device *dev) |
1306 | { | 1348 | { |
1307 | int i; | 1349 | struct sh_sci_priv *priv = platform_get_drvdata(dev); |
1350 | struct sci_port *p; | ||
1351 | unsigned long flags; | ||
1308 | 1352 | ||
1309 | for (i = 0; i < SCI_NPORTS; i++) { | 1353 | spin_lock_irqsave(&priv->lock, flags); |
1310 | struct sci_port *p = &sci_ports[i]; | 1354 | list_for_each_entry(p, &priv->ports, node) |
1355 | uart_resume_port(&sci_uart_driver, &p->port); | ||
1311 | 1356 | ||
1312 | if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) | 1357 | spin_unlock_irqrestore(&priv->lock, flags); |
1313 | uart_resume_port(&sci_uart_driver, &p->port); | ||
1314 | } | ||
1315 | 1358 | ||
1316 | return 0; | 1359 | return 0; |
1317 | } | 1360 | } |