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