[go: nahoru, domu]

1cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummo/* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems.
27a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller *
37a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
47a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller */
57a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
6d959f7319adf58e4bfcada15cc088941dee79f36Jingoo Han#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7d959f7319adf58e4bfcada15cc088941dee79f36Jingoo Han
87a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller#include <linux/kernel.h>
97a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller#include <linux/module.h>
107a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller#include <linux/delay.h>
117a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller#include <linux/init.h>
127a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller#include <linux/rtc.h>
137a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller#include <linux/platform_device.h>
147a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
157a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller#include <asm/hypervisor.h>
167a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
177a138ede551c5282c1b81d191bdd4aa989b119a8David S. Millerstatic unsigned long hypervisor_get_time(void)
187a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller{
197a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	unsigned long ret, time;
207a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	int retries = 10000;
217a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
227a138ede551c5282c1b81d191bdd4aa989b119a8David S. Millerretry:
237a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	ret = sun4v_tod_get(&time);
247a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	if (ret == HV_EOK)
257a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		return time;
267a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	if (ret == HV_EWOULDBLOCK) {
277a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		if (--retries > 0) {
287a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller			udelay(100);
297a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller			goto retry;
307a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		}
31d959f7319adf58e4bfcada15cc088941dee79f36Jingoo Han		pr_warn("tod_get() timed out.\n");
327a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		return 0;
337a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	}
34d959f7319adf58e4bfcada15cc088941dee79f36Jingoo Han	pr_warn("tod_get() not supported.\n");
357a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	return 0;
367a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller}
377a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
387a138ede551c5282c1b81d191bdd4aa989b119a8David S. Millerstatic int sun4v_read_time(struct device *dev, struct rtc_time *tm)
397a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller{
40cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummo	rtc_time_to_tm(hypervisor_get_time(), tm);
417a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	return 0;
427a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller}
437a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
447a138ede551c5282c1b81d191bdd4aa989b119a8David S. Millerstatic int hypervisor_set_time(unsigned long secs)
457a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller{
467a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	unsigned long ret;
477a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	int retries = 10000;
487a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
497a138ede551c5282c1b81d191bdd4aa989b119a8David S. Millerretry:
507a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	ret = sun4v_tod_set(secs);
517a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	if (ret == HV_EOK)
527a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		return 0;
537a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	if (ret == HV_EWOULDBLOCK) {
547a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		if (--retries > 0) {
557a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller			udelay(100);
567a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller			goto retry;
577a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		}
58d959f7319adf58e4bfcada15cc088941dee79f36Jingoo Han		pr_warn("tod_set() timed out.\n");
597a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		return -EAGAIN;
607a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	}
61d959f7319adf58e4bfcada15cc088941dee79f36Jingoo Han	pr_warn("tod_set() not supported.\n");
627a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	return -EOPNOTSUPP;
637a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller}
647a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
657a138ede551c5282c1b81d191bdd4aa989b119a8David S. Millerstatic int sun4v_set_time(struct device *dev, struct rtc_time *tm)
667a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller{
67cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummo	unsigned long secs;
687a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	int err;
697a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
707a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	err = rtc_tm_to_time(tm, &secs);
717a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	if (err)
727a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		return err;
737a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
74cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummo	return hypervisor_set_time(secs);
757a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller}
767a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
777a138ede551c5282c1b81d191bdd4aa989b119a8David S. Millerstatic const struct rtc_class_ops sun4v_rtc_ops = {
787a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	.read_time	= sun4v_read_time,
797a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	.set_time	= sun4v_set_time,
807a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller};
817a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
82cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummostatic int __init sun4v_rtc_probe(struct platform_device *pdev)
837a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller{
84cc40d642f8f0cd036a105ac0237138fd1812a94fJingoo Han	struct rtc_device *rtc;
85cc40d642f8f0cd036a105ac0237138fd1812a94fJingoo Han
86cc40d642f8f0cd036a105ac0237138fd1812a94fJingoo Han	rtc = devm_rtc_device_register(&pdev->dev, "sun4v",
87cc40d642f8f0cd036a105ac0237138fd1812a94fJingoo Han				&sun4v_rtc_ops, THIS_MODULE);
88cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummo	if (IS_ERR(rtc))
89cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummo		return PTR_ERR(rtc);
90cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummo
91cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummo	platform_set_drvdata(pdev, rtc);
927a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	return 0;
937a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller}
947a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
957a138ede551c5282c1b81d191bdd4aa989b119a8David S. Millerstatic struct platform_driver sun4v_rtc_driver = {
967a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	.driver		= {
977a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		.name	= "rtc-sun4v",
987a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller		.owner	= THIS_MODULE,
997a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller	},
1007a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller};
1017a138ede551c5282c1b81d191bdd4aa989b119a8David S. Miller
10261ce8256cb35eb84b6c5d167a023e1235e3bdcfcJingoo Hanmodule_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
103cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro Zummo
104cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro ZummoMODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
105cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro ZummoMODULE_DESCRIPTION("SUN4V RTC driver");
106cecf61bdee426a3e0a014f7e26990d09c71ed458Alessandro ZummoMODULE_LICENSE("GPL");
107