2007-10-27 00:17:01 -07:00
/* linux/arch/sparc/kernel/time.c
2005-04-16 15:20:36 -07:00
*
2007-10-27 00:17:01 -07:00
* Copyright ( C ) 1995 David S . Miller ( davem @ davemloft . net )
2005-04-16 15:20:36 -07:00
* Copyright ( C ) 1996 Thomas K . Dyas ( tdyas @ eden . rutgers . edu )
*
* Chris Davis ( cdavis @ cois . on . ca ) 03 / 27 / 1998
* Added support for the intersil on the sun4 / 4200
*
* Gleb Raiko ( rajko @ mech . math . msu . su ) 08 / 18 / 1998
* Support for MicroSPARC - IIep , PCI CPU .
*
* This file handles the Sparc specific time handling details .
*
* 1997 - 09 - 10 Updated NTP code according to technical memorandum Jan ' 96
* " A Kernel Model for Precision Timekeeping " by Dave Mills
*/
# include <linux/errno.h>
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/param.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/interrupt.h>
# include <linux/time.h>
2008-09-03 15:52:38 -07:00
# include <linux/rtc.h>
# include <linux/rtc/m48t59.h>
2005-04-16 15:20:36 -07:00
# include <linux/timex.h>
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/ioport.h>
# include <linux/profile.h>
2008-08-27 04:05:35 -07:00
# include <linux/of.h>
2008-08-07 15:33:36 -07:00
# include <linux/of_device.h>
2008-09-03 15:52:38 -07:00
# include <linux/platform_device.h>
2005-04-16 15:20:36 -07:00
# include <asm/oplib.h>
2010-01-15 01:34:28 -08:00
# include <asm/timex.h>
2005-04-16 15:20:36 -07:00
# include <asm/timer.h>
# include <asm/system.h>
# include <asm/irq.h>
# include <asm/io.h>
# include <asm/idprom.h>
# include <asm/machines.h>
# include <asm/page.h>
# include <asm/pcic.h>
2006-10-08 14:30:44 +01:00
# include <asm/irq_regs.h>
2005-04-16 15:20:36 -07:00
2007-07-21 19:18:57 -07:00
# include "irq.h"
2005-04-16 15:20:36 -07:00
DEFINE_SPINLOCK ( rtc_lock ) ;
2009-01-08 16:58:05 -08:00
EXPORT_SYMBOL ( rtc_lock ) ;
2005-04-16 15:20:36 -07:00
static int set_rtc_mmss ( unsigned long ) ;
unsigned long profile_pc ( struct pt_regs * regs )
{
extern char __copy_user_begin [ ] , __copy_user_end [ ] ;
extern char __atomic_begin [ ] , __atomic_end [ ] ;
extern char __bzero_begin [ ] , __bzero_end [ ] ;
unsigned long pc = regs - > pc ;
if ( in_lock_functions ( pc ) | |
( pc > = ( unsigned long ) __copy_user_begin & &
pc < ( unsigned long ) __copy_user_end ) | |
( pc > = ( unsigned long ) __atomic_begin & &
pc < ( unsigned long ) __atomic_end ) | |
( pc > = ( unsigned long ) __bzero_begin & &
2006-12-17 16:18:47 -08:00
pc < ( unsigned long ) __bzero_end ) )
2005-04-16 15:20:36 -07:00
pc = regs - > u_regs [ UREG_RETPC ] ;
return pc ;
}
2006-10-17 19:21:48 -07:00
EXPORT_SYMBOL ( profile_pc ) ;
2005-04-16 15:20:36 -07:00
__volatile__ unsigned int * master_l10_counter ;
2010-01-15 01:34:28 -08:00
u32 ( * do_arch_gettimeoffset ) ( void ) ;
2010-03-03 19:57:27 -08:00
int update_persistent_clock ( struct timespec now )
{
return set_rtc_mmss ( now . tv_sec ) ;
}
2005-04-16 15:20:36 -07:00
/*
* timer_interrupt ( ) needs to keep up the real - time clock ,
2011-01-27 16:00:22 +01:00
* as well as call the " xtime_update() " routine every clocktick
2005-04-16 15:20:36 -07:00
*/
# define TICK_SIZE (tick_nsec / 1000)
2007-10-31 05:08:48 -04:00
static irqreturn_t timer_interrupt ( int dummy , void * dev_id )
2005-04-16 15:20:36 -07:00
{
# ifndef CONFIG_SMP
2006-10-08 14:30:44 +01:00
profile_tick ( CPU_PROFILING ) ;
2005-04-16 15:20:36 -07:00
# endif
clear_clock_irq ( ) ;
2011-01-27 16:00:22 +01:00
xtime_update ( 1 ) ;
2005-04-16 15:20:36 -07:00
2008-02-13 21:33:16 +01:00
# ifndef CONFIG_SMP
update_process_times ( user_mode ( get_irq_regs ( ) ) ) ;
# endif
2005-04-16 15:20:36 -07:00
return IRQ_HANDLED ;
}
2008-09-03 15:52:38 -07:00
static unsigned char mostek_read_byte ( struct device * dev , u32 ofs )
2005-04-16 15:20:36 -07:00
{
2008-09-03 15:52:38 -07:00
struct platform_device * pdev = to_platform_device ( dev ) ;
struct m48t59_plat_data * pdata = pdev - > dev . platform_data ;
2008-10-29 15:35:24 -07:00
return readb ( pdata - > ioaddr + ofs ) ;
2005-04-16 15:20:36 -07:00
}
2008-09-03 15:52:38 -07:00
static void mostek_write_byte ( struct device * dev , u32 ofs , u8 val )
2005-04-16 15:20:36 -07:00
{
2008-09-03 15:52:38 -07:00
struct platform_device * pdev = to_platform_device ( dev ) ;
struct m48t59_plat_data * pdata = pdev - > dev . platform_data ;
2008-10-29 15:35:24 -07:00
writeb ( val , pdata - > ioaddr + ofs ) ;
2005-04-16 15:20:36 -07:00
}
2008-09-03 15:52:38 -07:00
static struct m48t59_plat_data m48t59_data = {
. read_byte = mostek_read_byte ,
. write_byte = mostek_write_byte ,
} ;
/* resource is set at runtime */
static struct platform_device m48t59_rtc = {
. name = " rtc-m48t59 " ,
. id = 0 ,
. num_resources = 1 ,
. dev = {
. platform_data = & m48t59_data ,
} ,
} ;
2006-07-27 22:08:01 -07:00
2011-02-22 20:01:33 -07:00
static int __devinit clock_probe ( struct platform_device * op )
2005-04-16 15:20:36 -07:00
{
2010-04-13 16:12:29 -07:00
struct device_node * dp = op - > dev . of_node ;
2007-03-29 00:47:23 -07:00
const char * model = of_get_property ( dp , " model " , NULL ) ;
2005-04-16 15:20:36 -07:00
2006-06-29 14:36:52 -07:00
if ( ! model )
return - ENODEV ;
2005-04-16 15:20:36 -07:00
2011-03-24 16:34:52 -07:00
/* Only the primary RTC has an address property */
if ( ! of_find_property ( dp , " address " , NULL ) )
return - ENODEV ;
2008-09-03 15:52:38 -07:00
m48t59_rtc . resource = & op - > resource [ 0 ] ;
2006-06-29 14:36:52 -07:00
if ( ! strcmp ( model , " mk48t02 " ) ) {
2005-04-16 15:20:36 -07:00
/* Map the clock register io area read-only */
2008-09-03 15:52:38 -07:00
m48t59_data . ioaddr = of_ioremap ( & op - > resource [ 0 ] , 0 ,
2048 , " rtc-m48t59 " ) ;
m48t59_data . type = M48T59RTC_TYPE_M48T02 ;
2006-06-29 14:36:52 -07:00
} else if ( ! strcmp ( model , " mk48t08 " ) ) {
2008-09-03 15:52:38 -07:00
m48t59_data . ioaddr = of_ioremap ( & op - > resource [ 0 ] , 0 ,
8192 , " rtc-m48t59 " ) ;
m48t59_data . type = M48T59RTC_TYPE_M48T08 ;
2006-06-29 14:36:52 -07:00
} else
return - ENODEV ;
2005-04-16 15:20:36 -07:00
2008-09-03 15:52:38 -07:00
if ( platform_device_register ( & m48t59_rtc ) < 0 )
printk ( KERN_ERR " Registering RTC device failed \n " ) ;
2006-07-27 22:08:01 -07:00
2006-06-29 14:36:52 -07:00
return 0 ;
}
2008-08-31 01:23:17 -07:00
static struct of_device_id __initdata clock_match [ ] = {
2006-06-29 14:36:52 -07:00
{
. name = " eeprom " ,
} ,
{ } ,
} ;
2011-02-22 20:01:33 -07:00
static struct platform_driver clock_driver = {
2006-06-29 14:36:52 -07:00
. probe = clock_probe ,
2010-04-13 16:13:02 -07:00
. driver = {
. name = " rtc " ,
. owner = THIS_MODULE ,
. of_match_table = clock_match ,
2007-10-10 23:27:34 -07:00
} ,
2006-06-29 14:36:52 -07:00
} ;
/* Probe for the mostek real time clock chip. */
2006-07-27 22:08:01 -07:00
static int __init clock_init ( void )
2006-06-29 14:36:52 -07:00
{
2011-02-22 20:01:33 -07:00
return platform_driver_register ( & clock_driver ) ;
2005-04-16 15:20:36 -07:00
}
2006-07-27 22:08:01 -07:00
/* Must be after subsys_initcall() so that busses are probed. Must
* be before device_initcall ( ) because things like the RTC driver
* need to see the clock registers .
*/
fs_initcall ( clock_init ) ;
2005-04-16 15:20:36 -07:00
2010-01-15 01:34:28 -08:00
u32 sbus_do_gettimeoffset ( void )
2005-04-16 15:20:36 -07:00
{
2008-01-09 05:09:06 -08:00
unsigned long val = * master_l10_counter ;
unsigned long usec = ( val > > 10 ) & 0x1fffff ;
/* Limit hit? */
if ( val & 0x80000000 )
usec + = 1000000 / HZ ;
2010-01-15 01:34:28 -08:00
return usec * 1000 ;
2005-04-16 15:20:36 -07:00
}
2010-01-15 01:34:28 -08:00
u32 arch_gettimeoffset ( void )
2005-04-16 15:20:36 -07:00
{
2010-01-15 01:34:28 -08:00
if ( unlikely ( ! do_arch_gettimeoffset ) )
return 0 ;
return do_arch_gettimeoffset ( ) ;
2005-04-16 15:20:36 -07:00
}
2010-01-15 01:34:28 -08:00
static void __init sbus_time_init ( void )
2005-04-16 15:20:36 -07:00
{
2010-01-15 01:34:28 -08:00
do_arch_gettimeoffset = sbus_do_gettimeoffset ;
2005-04-16 15:20:36 -07:00
2010-01-15 01:34:28 -08:00
btfixup ( ) ;
2005-04-16 15:20:36 -07:00
2011-02-25 23:00:19 -08:00
sparc_irq_config . init_timers ( timer_interrupt ) ;
2010-01-15 01:34:28 -08:00
}
2005-04-16 15:20:36 -07:00
2010-01-15 01:34:28 -08:00
void __init time_init ( void )
{
2011-04-17 13:49:55 +02:00
if ( pcic_present ( ) )
2010-01-15 01:34:28 -08:00
pci_time_init ( ) ;
2011-04-17 13:49:55 +02:00
else
sbus_time_init ( ) ;
2005-04-16 15:20:36 -07:00
}
2010-01-15 01:34:28 -08:00
2008-09-03 15:52:38 -07:00
static int set_rtc_mmss ( unsigned long secs )
2005-04-16 15:20:36 -07:00
{
2008-09-03 15:52:38 -07:00
struct rtc_device * rtc = rtc_class_open ( " rtc0 " ) ;
2008-09-10 13:36:13 -07:00
int err = - 1 ;
2005-04-16 15:20:36 -07:00
2008-09-10 13:36:13 -07:00
if ( rtc ) {
err = rtc_set_mmss ( rtc , secs ) ;
rtc_class_close ( rtc ) ;
}
2005-04-16 15:20:36 -07:00
2008-09-10 13:36:13 -07:00
return err ;
2005-04-16 15:20:36 -07:00
}