2007-05-07 01:50:32 +04:00
/*
* Blackfin On - Chip Real Time Clock Driver
2008-02-06 12:38:51 +03:00
* Supports BF52 [ 257 ] / BF53 [ 123 ] / BF53 [ 467 ] / BF54 [ 24789 ]
2007-05-07 01:50:32 +04:00
*
2008-08-06 00:01:18 +04:00
* Copyright 2004 - 2008 Analog Devices Inc .
2007-05-07 01:50:32 +04:00
*
* Enter bugs at http : //blackfin.uclinux.org/
*
* Licensed under the GPL - 2 or later .
*/
/* The biggest issue we deal with in this driver is that register writes are
* synced to the RTC frequency of 1 Hz . So if you write to a register and
* attempt to write again before the first write has completed , the new write
* is simply discarded . This can easily be troublesome if userspace disables
* one event ( say periodic ) and then right after enables an event ( say alarm ) .
* Since all events are maintained in the same interrupt mask register , if
* we wrote to it to disable the first event and then wrote to it again to
* enable the second event , that second event would not be enabled as the
* write would be discarded and things quickly fall apart .
*
* To keep this delay from significantly degrading performance ( we , in theory ,
* would have to sleep for up to 1 second everytime we wanted to write a
* register ) , we only check the write pending status before we start to issue
* a new write . We bank on the idea that it doesnt matter when the sync
* happens so long as we don ' t attempt another write before it does . The only
* time userspace would take this penalty is when they try and do multiple
* operations right after another . . . but in this case , they need to take the
* sync penalty , so we should be OK .
*
* Also note that the RTC_ISTAT register does not suffer this penalty ; its
* writes to clear status registers complete immediately .
*/
2008-08-06 00:01:21 +04:00
/* It may seem odd that there is no SWCNT code in here (which would be exposed
* via the periodic interrupt event , or PIE ) . Since the Blackfin RTC peripheral
* runs in units of seconds ( N / HZ ) but the Linux framework runs in units of HZ
* ( 2 ^ N HZ ) , there is no point in keeping code that only provides 1 HZ PIEs .
* The same exact behavior can be accomplished by using the update interrupt
* event ( UIE ) . Maybe down the line the RTC peripheral will suck less in which
* case we can re - introduce PIE support .
*/
2007-05-07 01:50:32 +04:00
# include <linux/bcd.h>
2008-02-06 12:38:51 +03:00
# include <linux/completion.h>
# include <linux/delay.h>
2007-05-07 01:50:32 +04:00
# include <linux/init.h>
2008-02-06 12:38:51 +03:00
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/module.h>
2007-05-07 01:50:32 +04:00
# include <linux/platform_device.h>
2008-02-06 12:38:51 +03:00
# include <linux/rtc.h>
2007-05-07 01:50:32 +04:00
# include <linux/seq_file.h>
# include <asm/blackfin.h>
2008-02-06 12:38:49 +03:00
# define dev_dbg_stamp(dev) dev_dbg(dev, "%s:%i: here i am\n", __func__, __LINE__)
2007-05-07 01:50:32 +04:00
struct bfin_rtc {
struct rtc_device * rtc_dev ;
struct rtc_time rtc_alarm ;
2008-02-06 12:38:51 +03:00
u16 rtc_wrote_regs ;
2007-05-07 01:50:32 +04:00
} ;
/* Bit values for the ISTAT / ICTL registers */
# define RTC_ISTAT_WRITE_COMPLETE 0x8000
# define RTC_ISTAT_WRITE_PENDING 0x4000
# define RTC_ISTAT_ALARM_DAY 0x0040
# define RTC_ISTAT_24HR 0x0020
# define RTC_ISTAT_HOUR 0x0010
# define RTC_ISTAT_MIN 0x0008
# define RTC_ISTAT_SEC 0x0004
# define RTC_ISTAT_ALARM 0x0002
# define RTC_ISTAT_STOPWATCH 0x0001
/* Shift values for RTC_STAT register */
# define DAY_BITS_OFF 17
# define HOUR_BITS_OFF 12
# define MIN_BITS_OFF 6
# define SEC_BITS_OFF 0
/* Some helper functions to convert between the common RTC notion of time
2008-02-06 12:38:47 +03:00
* and the internal Blackfin notion that is encoded in 32 bits .
2007-05-07 01:50:32 +04:00
*/
static inline u32 rtc_time_to_bfin ( unsigned long now )
{
u32 sec = ( now % 60 ) ;
u32 min = ( now % ( 60 * 60 ) ) / 60 ;
u32 hour = ( now % ( 60 * 60 * 24 ) ) / ( 60 * 60 ) ;
u32 days = ( now / ( 60 * 60 * 24 ) ) ;
return ( sec < < SEC_BITS_OFF ) +
( min < < MIN_BITS_OFF ) +
( hour < < HOUR_BITS_OFF ) +
( days < < DAY_BITS_OFF ) ;
}
static inline unsigned long rtc_bfin_to_time ( u32 rtc_bfin )
{
return ( ( ( rtc_bfin > > SEC_BITS_OFF ) & 0x003F ) ) +
( ( ( rtc_bfin > > MIN_BITS_OFF ) & 0x003F ) * 60 ) +
( ( ( rtc_bfin > > HOUR_BITS_OFF ) & 0x001F ) * 60 * 60 ) +
( ( ( rtc_bfin > > DAY_BITS_OFF ) & 0x7FFF ) * 60 * 60 * 24 ) ;
}
static inline void rtc_bfin_to_tm ( u32 rtc_bfin , struct rtc_time * tm )
{
rtc_time_to_tm ( rtc_bfin_to_time ( rtc_bfin ) , tm ) ;
}
2008-02-06 12:38:51 +03:00
/**
* bfin_rtc_sync_pending - make sure pending writes have complete
*
* Wait for the previous write to a RTC register to complete .
2007-05-07 01:50:32 +04:00
* Unfortunately , we can ' t sleep here as that introduces a race condition when
* turning on interrupt events . Consider this :
* - process sets alarm
* - process enables alarm
* - process sleeps while waiting for rtc write to sync
* - interrupt fires while process is sleeping
* - interrupt acks the event by writing to ISTAT
* - interrupt sets the WRITE PENDING bit
* - interrupt handler finishes
* - process wakes up , sees WRITE PENDING bit set , goes to sleep
* - interrupt fires while process is sleeping
* If anyone can point out the obvious solution here , i ' m listening : ) . This
* shouldn ' t be an issue on an SMP or preempt system as this function should
* only be called with the rtc lock held .
2008-02-06 12:38:47 +03:00
*
* Other options :
* - disable PREN so the sync happens at 32.768 kHZ . . . but this changes the
* inc rate for all RTC registers from 1 HZ to 32.768 kHZ . . .
* - use the write complete IRQ
2007-05-07 01:50:32 +04:00
*/
2008-02-06 12:38:51 +03:00
/*
static void bfin_rtc_sync_pending_polled ( void )
2007-05-07 01:50:32 +04:00
{
2008-02-06 12:38:51 +03:00
while ( ! ( bfin_read_RTC_ISTAT ( ) & RTC_ISTAT_WRITE_COMPLETE ) )
2007-05-07 01:50:32 +04:00
if ( ! ( bfin_read_RTC_ISTAT ( ) & RTC_ISTAT_WRITE_PENDING ) )
break ;
bfin_write_RTC_ISTAT ( RTC_ISTAT_WRITE_COMPLETE ) ;
}
2008-02-06 12:38:51 +03:00
*/
static DECLARE_COMPLETION ( bfin_write_complete ) ;
static void bfin_rtc_sync_pending ( struct device * dev )
{
dev_dbg_stamp ( dev ) ;
while ( bfin_read_RTC_ISTAT ( ) & RTC_ISTAT_WRITE_PENDING )
wait_for_completion_timeout ( & bfin_write_complete , HZ * 5 ) ;
dev_dbg_stamp ( dev ) ;
}
2007-05-07 01:50:32 +04:00
2008-02-06 12:38:51 +03:00
/**
* bfin_rtc_reset - set RTC to sane / known state
*
* Initialize the RTC . Enable pre - scaler to scale RTC clock
* to 1 Hz and clear interrupt / status registers .
*/
2008-08-06 00:01:19 +04:00
static void bfin_rtc_reset ( struct device * dev , u16 rtc_ictl )
2007-05-07 01:50:32 +04:00
{
2008-02-06 12:38:49 +03:00
struct bfin_rtc * rtc = dev_get_drvdata ( dev ) ;
2008-02-06 12:38:51 +03:00
dev_dbg_stamp ( dev ) ;
bfin_rtc_sync_pending ( dev ) ;
2007-05-07 01:50:32 +04:00
bfin_write_RTC_PREN ( 0x1 ) ;
2008-08-06 00:01:19 +04:00
bfin_write_RTC_ICTL ( rtc_ictl ) ;
2007-05-07 01:50:32 +04:00
bfin_write_RTC_ALARM ( 0 ) ;
bfin_write_RTC_ISTAT ( 0xFFFF ) ;
2008-02-06 12:38:51 +03:00
rtc - > rtc_wrote_regs = 0 ;
2007-05-07 01:50:32 +04:00
}
2008-02-06 12:38:51 +03:00
/**
* bfin_rtc_interrupt - handle interrupt from RTC
*
* Since we handle all RTC events here , we have to make sure the requested
* interrupt is enabled ( in RTC_ICTL ) as the event status register ( RTC_ISTAT )
* always gets updated regardless of the interrupt being enabled . So when one
* even we care about ( e . g . stopwatch ) goes off , we don ' t want to turn around
* and say that other events have happened as well ( e . g . second ) . We do not
* have to worry about pending writes to the RTC_ICTL register as interrupts
* only fire if they are enabled in the RTC_ICTL register .
*/
2007-05-07 01:50:32 +04:00
static irqreturn_t bfin_rtc_interrupt ( int irq , void * dev_id )
{
2008-02-06 12:38:47 +03:00
struct device * dev = dev_id ;
struct bfin_rtc * rtc = dev_get_drvdata ( dev ) ;
2007-05-07 01:50:32 +04:00
unsigned long events = 0 ;
2008-02-06 12:38:51 +03:00
bool write_complete = false ;
u16 rtc_istat , rtc_ictl ;
2007-05-07 01:50:32 +04:00
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2007-05-07 01:50:32 +04:00
rtc_istat = bfin_read_RTC_ISTAT ( ) ;
2008-02-06 12:38:51 +03:00
rtc_ictl = bfin_read_RTC_ICTL ( ) ;
2007-05-07 01:50:32 +04:00
2008-02-06 12:38:51 +03:00
if ( rtc_istat & RTC_ISTAT_WRITE_COMPLETE ) {
bfin_write_RTC_ISTAT ( RTC_ISTAT_WRITE_COMPLETE ) ;
write_complete = true ;
complete ( & bfin_write_complete ) ;
2007-05-07 01:50:32 +04:00
}
2008-02-06 12:38:51 +03:00
if ( rtc_ictl & ( RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY ) ) {
if ( rtc_istat & ( RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY ) ) {
bfin_write_RTC_ISTAT ( RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY ) ;
events | = RTC_AF | RTC_IRQF ;
}
2007-05-07 01:50:32 +04:00
}
2008-02-06 12:38:51 +03:00
if ( rtc_ictl & RTC_ISTAT_SEC ) {
if ( rtc_istat & RTC_ISTAT_SEC ) {
bfin_write_RTC_ISTAT ( RTC_ISTAT_SEC ) ;
events | = RTC_UF | RTC_IRQF ;
}
}
2007-05-07 01:50:32 +04:00
2008-02-06 12:38:51 +03:00
if ( events )
rtc_update_irq ( rtc - > rtc_dev , 1 , events ) ;
2007-05-07 01:50:32 +04:00
2008-02-06 12:38:51 +03:00
if ( write_complete | | events )
return IRQ_HANDLED ;
else
return IRQ_NONE ;
2007-05-07 01:50:32 +04:00
}
2008-08-06 00:01:18 +04:00
static void bfin_rtc_int_set ( u16 rtc_int )
2008-02-06 12:38:51 +03:00
{
bfin_write_RTC_ISTAT ( rtc_int ) ;
bfin_write_RTC_ICTL ( bfin_read_RTC_ICTL ( ) | rtc_int ) ;
}
2008-08-06 00:01:18 +04:00
static void bfin_rtc_int_clear ( u16 rtc_int )
2008-02-06 12:38:51 +03:00
{
bfin_write_RTC_ICTL ( bfin_read_RTC_ICTL ( ) & rtc_int ) ;
}
static void bfin_rtc_int_set_alarm ( struct bfin_rtc * rtc )
{
/* Blackfin has different bits for whether the alarm is
* more than 24 hours away .
*/
2008-08-06 00:01:18 +04:00
bfin_rtc_int_set ( rtc - > rtc_alarm . tm_yday = = - 1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY ) ;
2008-02-06 12:38:51 +03:00
}
2007-05-07 01:50:32 +04:00
static int bfin_rtc_ioctl ( struct device * dev , unsigned int cmd , unsigned long arg )
{
struct bfin_rtc * rtc = dev_get_drvdata ( dev ) ;
2008-02-06 12:38:51 +03:00
int ret = 0 ;
2007-05-07 01:50:32 +04:00
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2007-05-07 01:50:32 +04:00
2008-02-06 12:38:51 +03:00
bfin_rtc_sync_pending ( dev ) ;
2007-05-07 01:50:32 +04:00
switch ( cmd ) {
case RTC_UIE_ON :
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2008-08-06 00:01:18 +04:00
bfin_rtc_int_set ( RTC_ISTAT_SEC ) ;
2008-02-06 12:38:51 +03:00
break ;
2007-05-07 01:50:32 +04:00
case RTC_UIE_OFF :
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2008-08-06 00:01:18 +04:00
bfin_rtc_int_clear ( ~ RTC_ISTAT_SEC ) ;
2008-02-06 12:38:51 +03:00
break ;
2007-05-07 01:50:32 +04:00
2008-02-06 12:38:51 +03:00
case RTC_AIE_ON :
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2008-02-06 12:38:51 +03:00
bfin_rtc_int_set_alarm ( rtc ) ;
break ;
2007-05-07 01:50:32 +04:00
case RTC_AIE_OFF :
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2008-08-06 00:01:18 +04:00
bfin_rtc_int_clear ( ~ ( RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY ) ) ;
2008-02-06 12:38:51 +03:00
break ;
default :
dev_dbg_stamp ( dev ) ;
ret = - ENOIOCTLCMD ;
2007-05-07 01:50:32 +04:00
}
2008-02-06 12:38:51 +03:00
return ret ;
2007-05-07 01:50:32 +04:00
}
static int bfin_rtc_read_time ( struct device * dev , struct rtc_time * tm )
{
struct bfin_rtc * rtc = dev_get_drvdata ( dev ) ;
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2007-05-07 01:50:32 +04:00
2008-02-06 12:38:51 +03:00
if ( rtc - > rtc_wrote_regs & 0x1 )
bfin_rtc_sync_pending ( dev ) ;
2007-05-07 01:50:32 +04:00
rtc_bfin_to_tm ( bfin_read_RTC_STAT ( ) , tm ) ;
return 0 ;
}
static int bfin_rtc_set_time ( struct device * dev , struct rtc_time * tm )
{
struct bfin_rtc * rtc = dev_get_drvdata ( dev ) ;
int ret ;
unsigned long now ;
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2007-05-07 01:50:32 +04:00
ret = rtc_tm_to_time ( tm , & now ) ;
if ( ret = = 0 ) {
2008-02-06 12:38:51 +03:00
if ( rtc - > rtc_wrote_regs & 0x1 )
bfin_rtc_sync_pending ( dev ) ;
2007-05-07 01:50:32 +04:00
bfin_write_RTC_STAT ( rtc_time_to_bfin ( now ) ) ;
2008-02-06 12:38:51 +03:00
rtc - > rtc_wrote_regs = 0x1 ;
2007-05-07 01:50:32 +04:00
}
return ret ;
}
static int bfin_rtc_read_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
struct bfin_rtc * rtc = dev_get_drvdata ( dev ) ;
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2008-02-06 12:38:50 +03:00
alrm - > time = rtc - > rtc_alarm ;
2008-02-06 12:38:51 +03:00
bfin_rtc_sync_pending ( dev ) ;
2008-02-06 12:38:49 +03:00
alrm - > enabled = ! ! ( bfin_read_RTC_ICTL ( ) & ( RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY ) ) ;
2007-05-07 01:50:32 +04:00
return 0 ;
}
static int bfin_rtc_set_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
struct bfin_rtc * rtc = dev_get_drvdata ( dev ) ;
2008-02-06 12:38:51 +03:00
unsigned long rtc_alarm ;
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2008-02-06 12:38:51 +03:00
if ( rtc_tm_to_time ( & alrm - > time , & rtc_alarm ) )
return - EINVAL ;
2008-02-06 12:38:49 +03:00
rtc - > rtc_alarm = alrm - > time ;
2008-02-06 12:38:51 +03:00
bfin_rtc_sync_pending ( dev ) ;
bfin_write_RTC_ALARM ( rtc_time_to_bfin ( rtc_alarm ) ) ;
if ( alrm - > enabled )
bfin_rtc_int_set_alarm ( rtc ) ;
2007-05-07 01:50:32 +04:00
return 0 ;
}
static int bfin_rtc_proc ( struct device * dev , struct seq_file * seq )
{
2008-02-06 12:38:48 +03:00
# define yesno(x) ((x) ? "yes" : "no")
2007-05-07 01:50:32 +04:00
u16 ictl = bfin_read_RTC_ICTL ( ) ;
2008-02-06 12:38:49 +03:00
dev_dbg_stamp ( dev ) ;
2008-02-06 12:38:48 +03:00
seq_printf ( seq ,
" alarm_IRQ \t : %s \n "
" wkalarm_IRQ \t : %s \n "
2008-08-06 00:01:21 +04:00
" seconds_IRQ \t : %s \n " ,
2008-02-06 12:38:48 +03:00
yesno ( ictl & RTC_ISTAT_ALARM ) ,
yesno ( ictl & RTC_ISTAT_ALARM_DAY ) ,
2008-08-06 00:01:21 +04:00
yesno ( ictl & RTC_ISTAT_SEC ) ) ;
2007-05-07 01:50:32 +04:00
return 0 ;
2008-02-06 12:38:48 +03:00
# undef yesno
2007-05-07 01:50:32 +04:00
}
static struct rtc_class_ops bfin_rtc_ops = {
. ioctl = bfin_rtc_ioctl ,
. read_time = bfin_rtc_read_time ,
. set_time = bfin_rtc_set_time ,
. read_alarm = bfin_rtc_read_alarm ,
. set_alarm = bfin_rtc_set_alarm ,
. proc = bfin_rtc_proc ,
} ;
static int __devinit bfin_rtc_probe ( struct platform_device * pdev )
{
struct bfin_rtc * rtc ;
2008-08-21 01:09:01 +04:00
struct device * dev = & pdev - > dev ;
2007-05-07 01:50:32 +04:00
int ret = 0 ;
2008-08-21 01:09:03 +04:00
unsigned long timeout ;
2007-05-07 01:50:32 +04:00
2008-08-21 01:09:01 +04:00
dev_dbg_stamp ( dev ) ;
2007-05-07 01:50:32 +04:00
2008-08-21 01:09:01 +04:00
/* Allocate memory for our RTC struct */
2007-05-07 01:50:32 +04:00
rtc = kzalloc ( sizeof ( * rtc ) , GFP_KERNEL ) ;
if ( unlikely ( ! rtc ) )
return - ENOMEM ;
2008-08-21 01:09:01 +04:00
platform_set_drvdata ( pdev , rtc ) ;
2008-08-21 01:09:02 +04:00
device_init_wakeup ( dev , 1 ) ;
2007-05-07 01:50:32 +04:00
2008-08-21 01:09:01 +04:00
/* Grab the IRQ and init the hardware */
ret = request_irq ( IRQ_RTC , bfin_rtc_interrupt , IRQF_SHARED , pdev - > name , dev ) ;
if ( unlikely ( ret ) )
2007-05-07 01:50:32 +04:00
goto err ;
2008-08-21 01:09:03 +04:00
/* sometimes the bootloader touched things, but the write complete was not
* enabled , so let ' s just do a quick timeout here since the IRQ will not fire . . .
*/
timeout = jiffies + HZ ;
while ( bfin_read_RTC_ISTAT ( ) & RTC_ISTAT_WRITE_PENDING )
if ( time_after ( jiffies , timeout ) )
break ;
2008-08-21 01:09:01 +04:00
bfin_rtc_reset ( dev , RTC_ISTAT_WRITE_COMPLETE ) ;
2008-08-06 00:01:21 +04:00
bfin_write_RTC_SWCNT ( 0 ) ;
2007-05-07 01:50:32 +04:00
2008-08-21 01:09:01 +04:00
/* Register our RTC with the RTC framework */
rtc - > rtc_dev = rtc_device_register ( pdev - > name , dev , & bfin_rtc_ops , THIS_MODULE ) ;
if ( unlikely ( IS_ERR ( rtc ) ) ) {
ret = PTR_ERR ( rtc - > rtc_dev ) ;
goto err_irq ;
}
2007-05-07 01:50:32 +04:00
return 0 ;
2008-08-21 01:09:01 +04:00
err_irq :
free_irq ( IRQ_RTC , dev ) ;
2008-02-06 12:38:47 +03:00
err :
2007-05-07 01:50:32 +04:00
kfree ( rtc ) ;
return ret ;
}
static int __devexit bfin_rtc_remove ( struct platform_device * pdev )
{
struct bfin_rtc * rtc = platform_get_drvdata ( pdev ) ;
2008-08-21 01:09:01 +04:00
struct device * dev = & pdev - > dev ;
2007-05-07 01:50:32 +04:00
2008-08-21 01:09:01 +04:00
bfin_rtc_reset ( dev , 0 ) ;
free_irq ( IRQ_RTC , dev ) ;
2007-05-07 01:50:32 +04:00
rtc_device_unregister ( rtc - > rtc_dev ) ;
platform_set_drvdata ( pdev , NULL ) ;
kfree ( rtc ) ;
return 0 ;
}
2008-08-06 00:01:17 +04:00
# ifdef CONFIG_PM
static int bfin_rtc_suspend ( struct platform_device * pdev , pm_message_t state )
{
2008-08-06 00:01:20 +04:00
if ( device_may_wakeup ( & pdev - > dev ) ) {
2008-08-06 00:01:18 +04:00
enable_irq_wake ( IRQ_RTC ) ;
2008-08-06 00:01:20 +04:00
bfin_rtc_sync_pending ( & pdev - > dev ) ;
} else
2008-08-06 00:01:18 +04:00
bfin_rtc_int_clear ( - 1 ) ;
2008-08-06 00:01:18 +04:00
2008-08-06 00:01:17 +04:00
return 0 ;
}
static int bfin_rtc_resume ( struct platform_device * pdev )
{
2008-08-06 00:01:18 +04:00
if ( device_may_wakeup ( & pdev - > dev ) )
disable_irq_wake ( IRQ_RTC ) ;
else
bfin_write_RTC_ISTAT ( - 1 ) ;
2008-08-06 00:01:17 +04:00
return 0 ;
}
2008-08-06 00:01:18 +04:00
# else
# define bfin_rtc_suspend NULL
# define bfin_rtc_resume NULL
2008-08-06 00:01:17 +04:00
# endif
2007-05-07 01:50:32 +04:00
static struct platform_driver bfin_rtc_driver = {
. driver = {
. name = " rtc-bfin " ,
. owner = THIS_MODULE ,
} ,
. probe = bfin_rtc_probe ,
. remove = __devexit_p ( bfin_rtc_remove ) ,
2008-08-06 00:01:17 +04:00
. suspend = bfin_rtc_suspend ,
. resume = bfin_rtc_resume ,
2007-05-07 01:50:32 +04:00
} ;
static int __init bfin_rtc_init ( void )
{
return platform_driver_register ( & bfin_rtc_driver ) ;
}
static void __exit bfin_rtc_exit ( void )
{
platform_driver_unregister ( & bfin_rtc_driver ) ;
}
module_init ( bfin_rtc_init ) ;
module_exit ( bfin_rtc_exit ) ;
MODULE_DESCRIPTION ( " Blackfin On-Chip Real Time Clock Driver " ) ;
MODULE_AUTHOR ( " Mike Frysinger <vapier@gentoo.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-04-11 08:29:25 +04:00
MODULE_ALIAS ( " platform:rtc-bfin " ) ;