2019-03-22 10:22:56 +03:00
// SPDX-License-Identifier: GPL-2.0
2008-11-15 03:37:54 +03:00
/* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems.
2016-10-31 21:55:27 +03:00
*
* Author : David S . Miller
2008-08-29 12:32:43 +04:00
*
* Copyright ( C ) 2008 David S . Miller < davem @ davemloft . net >
*/
2013-02-22 04:45:32 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2008-08-29 12:32:43 +04:00
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/rtc.h>
# include <linux/platform_device.h>
# include <asm/hypervisor.h>
static unsigned long hypervisor_get_time ( void )
{
unsigned long ret , time ;
int retries = 10000 ;
retry :
ret = sun4v_tod_get ( & time ) ;
if ( ret = = HV_EOK )
return time ;
if ( ret = = HV_EWOULDBLOCK ) {
if ( - - retries > 0 ) {
udelay ( 100 ) ;
goto retry ;
}
2013-02-22 04:45:32 +04:00
pr_warn ( " tod_get() timed out. \n " ) ;
2008-08-29 12:32:43 +04:00
return 0 ;
}
2013-02-22 04:45:32 +04:00
pr_warn ( " tod_get() not supported. \n " ) ;
2008-08-29 12:32:43 +04:00
return 0 ;
}
static int sun4v_read_time ( struct device * dev , struct rtc_time * tm )
{
2019-03-22 10:22:54 +03:00
rtc_time64_to_tm ( hypervisor_get_time ( ) , tm ) ;
2008-08-29 12:32:43 +04:00
return 0 ;
}
static int hypervisor_set_time ( unsigned long secs )
{
unsigned long ret ;
int retries = 10000 ;
retry :
ret = sun4v_tod_set ( secs ) ;
if ( ret = = HV_EOK )
return 0 ;
if ( ret = = HV_EWOULDBLOCK ) {
if ( - - retries > 0 ) {
udelay ( 100 ) ;
goto retry ;
}
2013-02-22 04:45:32 +04:00
pr_warn ( " tod_set() timed out. \n " ) ;
2008-08-29 12:32:43 +04:00
return - EAGAIN ;
}
2013-02-22 04:45:32 +04:00
pr_warn ( " tod_set() not supported. \n " ) ;
2008-08-29 12:32:43 +04:00
return - EOPNOTSUPP ;
}
static int sun4v_set_time ( struct device * dev , struct rtc_time * tm )
{
2019-03-22 10:22:54 +03:00
return hypervisor_set_time ( rtc_tm_to_time64 ( tm ) ) ;
2008-08-29 12:32:43 +04:00
}
static const struct rtc_class_ops sun4v_rtc_ops = {
. read_time = sun4v_read_time ,
. set_time = sun4v_set_time ,
} ;
2008-11-15 03:37:54 +03:00
static int __init sun4v_rtc_probe ( struct platform_device * pdev )
2008-08-29 12:32:43 +04:00
{
2013-04-30 03:19:51 +04:00
struct rtc_device * rtc ;
2019-03-22 10:22:55 +03:00
rtc = devm_rtc_allocate_device ( & pdev - > dev ) ;
2008-11-15 03:37:54 +03:00
if ( IS_ERR ( rtc ) )
return PTR_ERR ( rtc ) ;
2019-03-22 10:22:55 +03:00
rtc - > ops = & sun4v_rtc_ops ;
rtc - > range_max = U64_MAX ;
2008-11-15 03:37:54 +03:00
platform_set_drvdata ( pdev , rtc ) ;
2019-03-22 10:22:55 +03:00
return rtc_register_device ( rtc ) ;
2008-08-29 12:32:43 +04:00
}
static struct platform_driver sun4v_rtc_driver = {
. driver = {
. name = " rtc-sun4v " ,
} ,
} ;
2016-10-31 21:55:27 +03:00
builtin_platform_driver_probe ( sun4v_rtc_driver , sun4v_rtc_probe ) ;