diff options
author | Jingoo Han <jg1.han@samsung.com> | 2010-12-17 02:45:46 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-12-20 11:05:43 -0500 |
commit | 4959212c18669f254daa0ae796ad676b67939ba2 (patch) | |
tree | ad7957b2e9bac2687c14a9f92eff6637d127fe3d /drivers/video/s3c-fb.c | |
parent | 3b80ffdef001ac7ff53bdcb80ad2baadb5953f91 (diff) |
s3c-fb: add support for runtime pm
This patch adds support for runtime pm using the functions.
- pm_runtime_get_sync()
- pm_runtime_put_sync()
pm_runtime_get_sync() and pm_runtime_put_sync() are called when
open or release function of framebufer driver is called to inform
the system if hardware is idle or not.
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/video/s3c-fb.c')
-rw-r--r-- | drivers/video/s3c-fb.c | 111 |
1 files changed, 107 insertions, 4 deletions
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index f9aca9d13d1b..83ce9a04d872 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/uaccess.h> | 24 | #include <linux/uaccess.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/pm_runtime.h> | ||
26 | 27 | ||
27 | #include <mach/map.h> | 28 | #include <mach/map.h> |
28 | #include <plat/regs-fb-v4.h> | 29 | #include <plat/regs-fb-v4.h> |
@@ -1013,8 +1014,30 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
1013 | return ret; | 1014 | return ret; |
1014 | } | 1015 | } |
1015 | 1016 | ||
1017 | static int s3c_fb_open(struct fb_info *info, int user) | ||
1018 | { | ||
1019 | struct s3c_fb_win *win = info->par; | ||
1020 | struct s3c_fb *sfb = win->parent; | ||
1021 | |||
1022 | pm_runtime_get_sync(sfb->dev); | ||
1023 | |||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | static int s3c_fb_release(struct fb_info *info, int user) | ||
1028 | { | ||
1029 | struct s3c_fb_win *win = info->par; | ||
1030 | struct s3c_fb *sfb = win->parent; | ||
1031 | |||
1032 | pm_runtime_put_sync(sfb->dev); | ||
1033 | |||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1016 | static struct fb_ops s3c_fb_ops = { | 1037 | static struct fb_ops s3c_fb_ops = { |
1017 | .owner = THIS_MODULE, | 1038 | .owner = THIS_MODULE, |
1039 | .fb_open = s3c_fb_open, | ||
1040 | .fb_release = s3c_fb_release, | ||
1018 | .fb_check_var = s3c_fb_check_var, | 1041 | .fb_check_var = s3c_fb_check_var, |
1019 | .fb_set_par = s3c_fb_set_par, | 1042 | .fb_set_par = s3c_fb_set_par, |
1020 | .fb_blank = s3c_fb_blank, | 1043 | .fb_blank = s3c_fb_blank, |
@@ -1322,6 +1345,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1322 | 1345 | ||
1323 | clk_enable(sfb->bus_clk); | 1346 | clk_enable(sfb->bus_clk); |
1324 | 1347 | ||
1348 | pm_runtime_enable(sfb->dev); | ||
1349 | |||
1325 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1350 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1326 | if (!res) { | 1351 | if (!res) { |
1327 | dev_err(dev, "failed to find registers\n"); | 1352 | dev_err(dev, "failed to find registers\n"); |
@@ -1360,6 +1385,9 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1360 | 1385 | ||
1361 | dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); | 1386 | dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); |
1362 | 1387 | ||
1388 | platform_set_drvdata(pdev, sfb); | ||
1389 | pm_runtime_get_sync(sfb->dev); | ||
1390 | |||
1363 | /* setup gpio and output polarity controls */ | 1391 | /* setup gpio and output polarity controls */ |
1364 | 1392 | ||
1365 | pd->setup_gpio(); | 1393 | pd->setup_gpio(); |
@@ -1400,6 +1428,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1400 | } | 1428 | } |
1401 | 1429 | ||
1402 | platform_set_drvdata(pdev, sfb); | 1430 | platform_set_drvdata(pdev, sfb); |
1431 | pm_runtime_put_sync(sfb->dev); | ||
1403 | 1432 | ||
1404 | return 0; | 1433 | return 0; |
1405 | 1434 | ||
@@ -1434,6 +1463,8 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) | |||
1434 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | 1463 | struct s3c_fb *sfb = platform_get_drvdata(pdev); |
1435 | int win; | 1464 | int win; |
1436 | 1465 | ||
1466 | pm_runtime_get_sync(sfb->dev); | ||
1467 | |||
1437 | for (win = 0; win < S3C_FB_MAX_WIN; win++) | 1468 | for (win = 0; win < S3C_FB_MAX_WIN; win++) |
1438 | if (sfb->windows[win]) | 1469 | if (sfb->windows[win]) |
1439 | s3c_fb_release_win(sfb, sfb->windows[win]); | 1470 | s3c_fb_release_win(sfb, sfb->windows[win]); |
@@ -1450,12 +1481,74 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) | |||
1450 | 1481 | ||
1451 | kfree(sfb); | 1482 | kfree(sfb); |
1452 | 1483 | ||
1484 | pm_runtime_put_sync(sfb->dev); | ||
1485 | pm_runtime_disable(sfb->dev); | ||
1486 | |||
1453 | return 0; | 1487 | return 0; |
1454 | } | 1488 | } |
1455 | 1489 | ||
1456 | #ifdef CONFIG_PM | 1490 | #ifdef CONFIG_PM |
1457 | static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state) | 1491 | static int s3c_fb_suspend(struct device *dev) |
1492 | { | ||
1493 | struct platform_device *pdev = to_platform_device(dev); | ||
1494 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | ||
1495 | struct s3c_fb_win *win; | ||
1496 | int win_no; | ||
1497 | |||
1498 | for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { | ||
1499 | win = sfb->windows[win_no]; | ||
1500 | if (!win) | ||
1501 | continue; | ||
1502 | |||
1503 | /* use the blank function to push into power-down */ | ||
1504 | s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); | ||
1505 | } | ||
1506 | |||
1507 | clk_disable(sfb->bus_clk); | ||
1508 | return 0; | ||
1509 | } | ||
1510 | |||
1511 | static int s3c_fb_resume(struct device *dev) | ||
1512 | { | ||
1513 | struct platform_device *pdev = to_platform_device(dev); | ||
1514 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | ||
1515 | struct s3c_fb_platdata *pd = sfb->pdata; | ||
1516 | struct s3c_fb_win *win; | ||
1517 | int win_no; | ||
1518 | |||
1519 | clk_enable(sfb->bus_clk); | ||
1520 | |||
1521 | /* setup registers */ | ||
1522 | writel(pd->vidcon1, sfb->regs + VIDCON1); | ||
1523 | |||
1524 | /* zero all windows before we do anything */ | ||
1525 | for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) | ||
1526 | s3c_fb_clear_win(sfb, win_no); | ||
1527 | |||
1528 | for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { | ||
1529 | void __iomem *regs = sfb->regs + sfb->variant.keycon; | ||
1530 | |||
1531 | regs += (win_no * 8); | ||
1532 | writel(0xffffff, regs + WKEYCON0); | ||
1533 | writel(0xffffff, regs + WKEYCON1); | ||
1534 | } | ||
1535 | |||
1536 | /* restore framebuffers */ | ||
1537 | for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { | ||
1538 | win = sfb->windows[win_no]; | ||
1539 | if (!win) | ||
1540 | continue; | ||
1541 | |||
1542 | dev_dbg(&pdev->dev, "resuming window %d\n", win_no); | ||
1543 | s3c_fb_set_par(win->fbinfo); | ||
1544 | } | ||
1545 | |||
1546 | return 0; | ||
1547 | } | ||
1548 | |||
1549 | int s3c_fb_runtime_suspend(struct device *dev) | ||
1458 | { | 1550 | { |
1551 | struct platform_device *pdev = to_platform_device(dev); | ||
1459 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | 1552 | struct s3c_fb *sfb = platform_get_drvdata(pdev); |
1460 | struct s3c_fb_win *win; | 1553 | struct s3c_fb_win *win; |
1461 | int win_no; | 1554 | int win_no; |
@@ -1473,8 +1566,9 @@ static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state) | |||
1473 | return 0; | 1566 | return 0; |
1474 | } | 1567 | } |
1475 | 1568 | ||
1476 | static int s3c_fb_resume(struct platform_device *pdev) | 1569 | int s3c_fb_runtime_resume(struct device *dev) |
1477 | { | 1570 | { |
1571 | struct platform_device *pdev = to_platform_device(dev); | ||
1478 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | 1572 | struct s3c_fb *sfb = platform_get_drvdata(pdev); |
1479 | struct s3c_fb_platdata *pd = sfb->pdata; | 1573 | struct s3c_fb_platdata *pd = sfb->pdata; |
1480 | struct s3c_fb_win *win; | 1574 | struct s3c_fb_win *win; |
@@ -1509,9 +1603,12 @@ static int s3c_fb_resume(struct platform_device *pdev) | |||
1509 | 1603 | ||
1510 | return 0; | 1604 | return 0; |
1511 | } | 1605 | } |
1606 | |||
1512 | #else | 1607 | #else |
1513 | #define s3c_fb_suspend NULL | 1608 | #define s3c_fb_suspend NULL |
1514 | #define s3c_fb_resume NULL | 1609 | #define s3c_fb_resume NULL |
1610 | #define s3c_fb_runtime_suspend NULL | ||
1611 | #define s3c_fb_runtime_resume NULL | ||
1515 | #endif | 1612 | #endif |
1516 | 1613 | ||
1517 | 1614 | ||
@@ -1710,15 +1807,21 @@ static struct platform_device_id s3c_fb_driver_ids[] = { | |||
1710 | }; | 1807 | }; |
1711 | MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); | 1808 | MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); |
1712 | 1809 | ||
1810 | static const struct dev_pm_ops s3cfb_pm_ops = { | ||
1811 | .suspend = s3c_fb_suspend, | ||
1812 | .resume = s3c_fb_resume, | ||
1813 | .runtime_suspend = s3c_fb_runtime_suspend, | ||
1814 | .runtime_resume = s3c_fb_runtime_resume, | ||
1815 | }; | ||
1816 | |||
1713 | static struct platform_driver s3c_fb_driver = { | 1817 | static struct platform_driver s3c_fb_driver = { |
1714 | .probe = s3c_fb_probe, | 1818 | .probe = s3c_fb_probe, |
1715 | .remove = __devexit_p(s3c_fb_remove), | 1819 | .remove = __devexit_p(s3c_fb_remove), |
1716 | .suspend = s3c_fb_suspend, | ||
1717 | .resume = s3c_fb_resume, | ||
1718 | .id_table = s3c_fb_driver_ids, | 1820 | .id_table = s3c_fb_driver_ids, |
1719 | .driver = { | 1821 | .driver = { |
1720 | .name = "s3c-fb", | 1822 | .name = "s3c-fb", |
1721 | .owner = THIS_MODULE, | 1823 | .owner = THIS_MODULE, |
1824 | .pm = &s3cfb_pm_ops, | ||
1722 | }, | 1825 | }, |
1723 | }; | 1826 | }; |
1724 | 1827 | ||