linux/drivers/rtc/rtc-bfin.c
<<
opti v/spa v/form va opti href="../linux+v3.9.5/drivers/rtc/rtc-bfin.c">opti vimg src="../.static/gfx/right.png" alt=">>">opv/spa opvspa class="lxr_search">optiopti vinput typopthidden" namoptnavtarget" 12opti vinput typopttext" namoptsearch" idptsearch">opti vbutt33.typoptsubmit">Searchopti Prefs v/a>opv/spa ti v/div ti vform ac12" ="ajax+*" method="post" onsubmit="return false;">opvinput typopthidden" namoptajax_lookup" idptajax_lookup" 12oti v/form oti vdiv class="headingbott3m">
vdiv idptfile_contents"
   1v/a>vspa
 class="comment">/*v/spa
	    2v/a>vspa
 class="comment"> * Blackfin On-Chip Real Time Clock Driverv/spa
	    3v/a>vspa
 class="comment"> *  Supports BF51x/BF52x/BF53[123]/BF53[467]/BF54xv/spa
	    4v/a>vspa
 class="comment"> *v/spa
	    5v/a>vspa
 class="comment"> * Copyright 2004-2010 Analog Devices Inc.v/spa
	    6v/a>vspa
 class="comment"> *v/spa
	    7v/a>vspa
 class="comment"> * Enter bugs at http://blackfin.uclinux.org/v/spa
	    8v/a>vspa
 class="comment"> *v/spa
	    9v/a>vspa
 class="comment"> * Licensed under the GPL-2 or later.v/spa
	   ue="a>vspa
 class="comment"> */v/spa
	   11v/a>   12v/a>vspa
 class="comment">/* The biggest issue we deal with in this driver is that register writes arev/spa
	   13v/a>vspa
 class="comment"> * synced to the RTC frequency of 1Hz.  So if you write to a register andv/spa
	   14v/a>vspa
 class="comment"> * attempt to write again before the first write has completed, the new writev/spa
	   15v/a>vspa
 class="comment"> * is simply discarded.  This ca
 easily be troublesome if userspace disablesv/spa
	   16v/a>vspa
 class="comment"> * one event (say periodic) and then right after enables a
 event (say alarm).v/spa
	   17v/a>vspa
 class="comment"> * Since all events are maintained in the same interrupt mask register, ifv/spa
	   18v/a>vspa
 class="comment"> * we wrote to it to disable the first event and then wrote to it again tov/spa
	   19v/a>vspa
 class="comment"> * enable the second event, that second event would not be enabled as thev/spa
	   2e="a>vspa
 class="comment"> * write would be discarded and things quickly fall apart.v/spa
	   21v/a>vspa
 class="comment"> *v/spa
	   22v/a>vspa
 class="comment"> * To keep this delay from significa
tly degrading performance (we, in theory,v/spa
	   23v/a>vspa
 class="comment"> * would have to sleep for up to 1 second every time we wa
ted to write av/spa
	   24v/a>vspa
 class="comment"> * register), we only check the write pending status before we start to issuev/spa
	   25v/a>vspa
 class="comment"> * a new write.  We bank on the idea that it doesn't matter when the syncv/spa
	   26v/a>vspa
 class="comment"> * happens so long as we don't attempt another write before it does.  The onlyv/spa
	   27v/a>vspa
 class="comment"> * time userspace would take this penalty is when they try and do multiplev/spa
	   28v/a>vspa
 class="comment"> * opera12"
s right after another ... but in this case, they need to take thev/spa
	   29v/a>vspa
 class="comment"> * sync penalty, so we should be OK.v/spa
	   3e="a>vspa
 class="comment"> *v/spa
	   31v/a>vspa
 class="comment"> * Also note that the RTC_ISTAT register does not suffer this penalty; itsv/spa
	   32v/a>vspa
 class="comment"> * writes to clear status registers complete immediately.v/spa
	   33v/a>vspa
 class="comment"> */v/spa
	   34v/a>   35v/a>vspa
 class="comment">/* It may seem odd that there is no SWCNT code in here (which would be exposedv/spa
	   36v/a>vspa
 class="comment"> * via the periodic interrupt event, or PIE).  Since the Blackfin RTC peripheralv/spa
	   37v/a>vspa
 class="comment"> * ru
s in units of seconds (N/HZ) but the Linux framowork ru
s in units of HZv/spa
	   38v/a>vspa
 class="comment"> * (2^N HZ), there is no point in keeping code that only provides 1 HZ PIEs.v/spa
	   39v/a>vspa
 class="comment"> * The same exact behavior ca
 be accomplished by using the update interruptv/spa
	   4e="a>vspa
 class="comment"> * event (UIE).  Maybe down the line the RTC peripheral will suck less in whichv/spa
	   41v/a>vspa
 class="comment"> * case we ca
 re-introduce PIE support.v/spa
	   42v/a>vspa
 class="comment"> */v/spa
	   43v/a>   44v/a>#include <linux/bcd.hv/a>>   45v/a>#include <linux/complet2"
.hv/a>>   46v/a>#include <linux/delay.hv/a>>   47v/a>#include <linux/init.hv/a>>   48v/a>#include <linux/interrupt.hv/a>>   49v/a>#include <linux/kernel.hv/a>>   50v/a>#include <linux/module.hv/a>>   51v/a>#include <linux/platform_device.hv/a>>   52v/a>#include <linux/rtc.hv/a>>   53v/a>#include <linux/seq_file.hv/a>>   54v/a>#include <linux/slab.hv/a>>   55v/a>   56v/a>#include <asm/blackfin.hv/a>>   57v/a>   58v/a>#define dev_dbg_stampv/a>(devv/a>) dev_dbgv/a>(devv/a>, vspa
 class="string">"%s:%i: here i am\n"v/spa
	, __func__v/a>, va href="+code=__LINE__" class="sref">__LINE__v/a>)   59v/a>   60v/a>struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> {   61v/a>        struct va href="+code=rtc_device" class="sref">rtc_devicev/a> *va href="+code=rtc_dev" class="sref">rtc_devv/a>;   62v/a>        struct va href="+code=rtc_time" class="sref">rtc_timev/a> va href="+code=rtc_alarm" class="sref">rtc_alarmv/a>;   63v/a>        va href="+code=u16" class="sref">u16v/a> va href="+code=rtc_wrote_regs" class="sref">rtc_wrote_regsv/a>;   64v/a>};   65v/a>   66v/a>vspa
 class="comment">/* Bit 12  67v/a>#define RTC_ISTAT_WRITE_COMPLETEv/a>  0x8000   68v/a>#define RTC_ISTAT_WRITE_PENDINGv/a>   0x4000   69v/a>#define RTC_ISTAT_ALARM_DAYv/a>       0x0040   70v/a>#define RTC_ISTAT_24HRv/a>            0x0020   71v/a>#define RTC_ISTAT_HOURv/a>            0x0010   72v/a>#define RTC_ISTAT_MINv/a>             0x0008   73v/a>#define RTC_ISTAT_SECv/a>             0x0004   74v/a>#define RTC_ISTAT_ALARMv/a>           0x0002   75v/a>#define RTC_ISTAT_STOPWATCHv/a>       0x0001   76v/a>   77v/a>vspa
 class="comment">/* Shift 12  78v/a>#define DAY_BITS_OFFv/a>    17   79v/a>#define HOUR_BITS_OFFv/a>   12   80v/a>#define MIN_BITS_OFFv/a>    6   81v/a>#define SEC_BITS_OFFv/a>    0   82v/a>   83v/a>vspa
 class="comment">/* Some helper func12"
s to convert between the common RTC no6.33.of timev/spa
	   84v/a>vspa
 class="comment"> * and the internal Blackfin no6.33.that is encoded in 32bits.v/spa
	   85v/a>vspa
 class="comment"> */v/spa
	   86v/a>static inlinev/a> va href="+code=u32" class="sref">u32v/a> va href="+code=rtc_time_to_bfin" class="sref">rtc_time_to_bfinv/a>(unsigned long va href="+code=now" class="sref">nowv/a>)   87v/a>{   88v/a>        va href="+code=u32" class="sref">u32v/a> va href="+code=sec" class="sref">secv/a>  = (nowv/a> % 60);   89v/a>        va href="+code=u32" class="sref">u32v/a> va href="+code=min" class="sref">minv/a>  = (nowv/a> % (60 * 60)) / 60;   90v/a>        va href="+code=u32" class="sref">u32v/a> va href="+code=hour" class="sref">hourv/a> = (nowv/a> % (60 * 60 * 24)) / (60 * 60);   91v/a>        va href="+code=u32" class="sref">u32v/a> va href="+code=days" class="sref">daysv/a> = (nowv/a> / (60 * 60 * 24));   92v/a>        return (secv/a>  << SEC_BITS_OFFv/a>) +   93v/a>               (minv/a>  << MIN_BITS_OFFv/a>) +   94v/a>               (hourv/a> << HOUR_BITS_OFFv/a>) +   95v/a>               (daysv/a> << DAY_BITS_OFFv/a>);   96v/a>}   97v/a>static inlinev/a> unsigned long va href="+code=rtc_bfin_to_time" class="sref">rtc_bfin_to_timev/a>(u32v/a> va href="+code=rtc_bfin" class="sref">rtc_bfinv/a>)   98v/a>{   99v/a>        return (((rtc_bfinv/a> >> SEC_BITS_OFFv/a>)  & 0x003F)) +  100v/a>               (((rtc_bfinv/a> >> MIN_BITS_OFFv/a>)  & 0x003F) * 60) +  101v/a>               (((rtc_bfinv/a> >> HOUR_BITS_OFFv/a>) & 0x001F) * 60 * 60) +  102v/a>               (((rtc_bfinv/a> >> DAY_BITS_OFFv/a>)  & 0x7FFF) * 60 * 60 * 24);  103v/a>}  104v/a>static inlinev/a> void va href="+code=rtc_bfin_to_tm" class="sref">rtc_bfin_to_tmv/a>(u32v/a> va href="+code=rtc_bfin" class="sref">rtc_bfinv/a>, struct va href="+code=rtc_time" class="sref">rtc_timev/a> *va href="+code=tm" class="sref">tmv/a>)  105v/a>{  106v/a>        va href="+code=rtc_time_to_tm" class="sref">rtc_time_to_tmv/a>(rtc_bfin_to_timev/a>(rtc_bfinv/a>), va href="+code=tm" class="sref">tmv/a>);  107v/a>}  108v/a>  109v/a>vspa
 class="comment">/**v/spa
	  1ue="a>vspa
 class="comment"> *      bfin_rtc_sync_pending - make sure pending writes have completev/spa
	  111v/a>vspa
 class="comment"> *v/spa
	  112v/a>vspa
 class="comment"> * Wait for the previous write to a RTC register to complete.v/spa
	  113v/a>vspa
 class="comment"> * Unfortunately, we ca
't sleep here as that introduces a race condi6.33.whenv/spa
	  114v/a>vspa
 class="comment"> * turning 33.interrupt events.  Consider this:v/spa
	  115v/a>vspa
 class="comment"> *  - process sets alarmv/spa
	  116v/a>vspa
 class="comment"> *  - process enables alarmv/spa
	  117v/a>vspa
 class="comment"> *  - process sleeps while wai6.ng for rtc write to syncv/spa
	  118v/a>vspa
 class="comment"> *  - interrupt fires while process is sleep.ngv/spa
	  119v/a>vspa
 class="comment"> *  - interrupt acks the event by writing to ISTATv/spa
	  12e="a>vspa
 class="comment"> *  - interrupt sets the WRITE PENDING bitv/spa
	  121v/a>vspa
 class="comment"> *  - interrupt handler finishesv/spa
	  122v/a>vspa
 class="comment"> *  - process wakes up, sees WRITE PENDING bit set, goes to sleepv/spa
	  123v/a>vspa
 class="comment"> *  - interrupt fires while process is sleep.ngv/spa
	  124v/a>vspa
 class="comment"> * If anyone ca
 point out the obvious solu6.33.here, i'm listening :).  Thisv/spa
	  125v/a>vspa
 class="comment"> * should
't be an issue 33.an SMP or preempt system as this func12"
 shouldv/spa
	  126v/a>vspa
 class="comment"> * only be called with the rtc lock held.v/spa
	  127v/a>vspa
 class="comment"> *v/spa
	  128v/a>vspa
 class="comment"> * Other 3.12"
s:v/spa
	  129v/a>vspa
 class="comment"> *  - disable PREN so the sync happens at 32.768kHZ ... but this changes thev/spa
	  13e="a>vspa
 class="comment"> *    inc rate for all RTC registers from 1HZ to 32.768kHZ ...v/spa
	  131v/a>vspa
 class="comment"> *  - use the write complete IRQv/spa
	  132v/a>vspa
 class="comment"> */v/spa
	  133v/a>vspa
 class="comment">/*v/spa
	  134v/a>vspa
 class="comment">static void bfin_rtc_sync_pending_polled(void)v/spa
	  135v/a>vspa
 class="comment">{v/spa
	  136v/a>vspa
 class="comment">        while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE))v/spa
	  137v/a>vspa
 class="comment">                if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING))v/spa
	  138v/a>vspa
 class="comment">                        break;v/spa
	  139v/a>vspa
 class="comment">        bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);v/spa
	  14e="a>vspa
 class="comment">}v/spa
	  141v/a>vspa
 class="comment">*/v/spa
	  142v/a>static DECLARE_COMPLETIONv/a>(bfin_write_completev/a>);  143v/a>static void bfin_rtc_sync_pendingv/a>(struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a>)  144v/a>{  145v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  146v/a>        while (bfin_read_RTC_ISTATv/a>() & RTC_ISTAT_WRITE_PENDINGv/a>)  147v/a>                wai6_for_complet2"
_timeoutv/a>(&bfin_write_completev/a>, va href="+code=HZ" class="sref">HZv/a> * 5);  148v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  149v/a>}  150v/a>  151v/a>vspa
 class="comment">/**v/spa
	  152v/a>vspa
 class="comment"> *      bfin_rtc_reset - set RTC to sane/known statev/spa
	  153v/a>vspa
 class="comment"> *v/spa
	  154v/a>vspa
 class="comment"> * Initialize the RTC.  Enable pre-scaler to scale RTC clockv/spa
	  155v/a>vspa
 class="comment"> * to 1Hz and clear interrupt/status registers.v/spa
	  156v/a>vspa
 class="comment"> */v/spa
	  157v/a>static void bfin_rtc_resetv/a>(struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a>, va href="+code=u16" class="sref">u16v/a> va href="+code=rtc_ictl" class="sref">rtc_ictlv/a>)  158v/a>{  159v/a>        struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a> = va href="+code=dev_get_drvdata" class="sref">dev_get_drvdatav/a>(devv/a>);  160v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  161v/a>        va href="+code=bfin_rtc_sync_pending" class="sref">bfin_rtc_sync_pendingv/a>(devv/a>);  162v/a>        bfin_write_RTC_PRENv/a>(0x1);  163v/a>        va href="+code=bfin_write_RTC_ICTL" class="sref">bfin_write_RTC_ICTLv/a>(rtc_ictlv/a>);  164v/a>        va href="+code=bfin_write_RTC_ALARM" class="sref">bfin_write_RTC_ALARMv/a>(0);  165v/a>        va href="+code=bfin_write_RTC_ISTAT" class="sref">bfin_write_RTC_ISTATv/a>(0xFFFF);  166v/a>        va href="+code=rtc" class="sref">rtcv/a>->rtc_wrote_regsv/a> = 0;  167v/a>}  168v/a>  169v/a>vspa
 class="comment">/**v/spa
	  17e="a>vspa
 class="comment"> *      bfin_rtc_interrupt - handle interrupt from RTCv/spa
	  171v/a>vspa
 class="comment"> *v/spa
	  172v/a>vspa
 class="comment"> * Since we handle all RTC events here, we have to make sure the requestedv/spa
	  173v/a>vspa
 class="comment"> * interrupt is enabled (in RTC_ICTL) as the event status register (RTC_ISTAT)v/spa
	  174v/a>vspa
 class="comment"> * always gets updated regardless of the interrupt being enabled.  So when onev/spa
	  175v/a>vspa
 class="comment"> * even we care about (e.g. stopwatch) goes off, we don't wa
t to turn aroundv/spa
	  176v/a>vspa
 class="comment"> * and say that other events have happened as well (e.g. second).  We do no6v/spa
	  177v/a>vspa
 class="comment"> * have to worry about pending writes to the RTC_ICTL register as interruptsv/spa
	  178v/a>vspa
 class="comment"> * only fire if they are enabled in the RTC_ICTL register.v/spa
	  179v/a>vspa
 class="comment"> */v/spa
	  180v/a>static irqreturn_tv/a> va href="+code=bfin_rtc_interrupt" class="sref">bfin_rtc_interruptv/a>(int irqv/a>, void *va href="+code=dev_id" class="sref">dev_idv/a>)  181v/a>{  182v/a>        struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a> = va href="+code=dev_id" class="sref">dev_idv/a>;  183v/a>        struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a> = va href="+code=dev_get_drvdata" class="sref">dev_get_drvdatav/a>(devv/a>);  184v/a>        unsigned long va href="+code=events" class="sref">eventsv/a> = 0;  185v/a>        va href="+code=bool" class="sref">boolv/a> va href="+code=write_complete" class="sref">write_completev/a> = va href="+code=false" class="sref">falsev/a>;  186v/a>        va href="+code=u16" class="sref">u16v/a> va href="+code=rtc_istat" class="sref">rtc_istatv/a>, va href="+code=rtc_istat_clear" class="sref">rtc_istat_clearv/a>, va href="+code=rtc_ictl" class="sref">rtc_ictlv/a>, va href="+code=bits" class="sref">bitsv/a>;  187v/a>  188v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  189v/a>  190v/a>        va href="+code=rtc_istat" class="sref">rtc_istatv/a> = va href="+code=bfin_read_RTC_ISTAT" class="sref">bfin_read_RTC_ISTATv/a>();  191v/a>        va href="+code=rtc_ictl" class="sref">rtc_ictlv/a> = va href="+code=bfin_read_RTC_ICTL" class="sref">bfin_read_RTC_ICTLv/a>();  192v/a>        rtc_istat_clearv/a> = 0;  193v/a>  194v/a>        va href="+code=bits" class="sref">bitsv/a> = va href="+code=RTC_ISTAT_WRITE_COMPLETE" class="sref">RTC_ISTAT_WRITE_COMPLETEv/a>;  195v/a>        if (va href="+code=rtc_istat" class="sref">rtc_istatv/a> & bitsv/a>) {  196v/a>                rtc_istat_clearv/a> |= va href="+code=bits" class="sref">bitsv/a>;  197v/a>                write_completev/a> = va href="+code=true" class="sref">truev/a>;  198v/a>                completev/a>(&bfin_write_completev/a>);  199v/a>        }  200v/a>  201v/a>        va href="+code=bits" class="sref">bitsv/a> = (va href="+code=RTC_ISTAT_ALARM" class="sref">RTC_ISTAT_ALARMv/a> | RTC_ISTAT_ALARM_DAYv/a>);  202v/a>        if (va href="+code=rtc_ictl" class="sref">rtc_ictlv/a> & bitsv/a>) {  203v/a>                if (va href="+code=rtc_istat" class="sref">rtc_istatv/a> & bitsv/a>) {  204v/a>                        rtc_istat_clearv/a> |= va href="+code=bits" class="sref">bitsv/a>;  205v/a>                        eventsv/a> |= va href="+code=RTC_AF" class="sref">RTC_AFv/a> | RTC_IRQFv/a>;  206v/a>                }  207v/a>        }  208v/a>  209v/a>        va href="+code=bits" class="sref">bitsv/a> = va href="+code=RTC_ISTAT_SEC" class="sref">RTC_ISTAT_SECv/a>;  210v/a>        if (va href="+code=rtc_ictl" class="sref">rtc_ictlv/a> & bitsv/a>) {  211v/a>                if (va href="+code=rtc_istat" class="sref">rtc_istatv/a> & bitsv/a>) {  212v/a>                        rtc_istat_clearv/a> |= va href="+code=bits" class="sref">bitsv/a>;  213v/a>                        eventsv/a> |= va href="+code=RTC_UF" class="sref">RTC_UFv/a> | RTC_IRQFv/a>;  214v/a>                }  215v/a>        }  216v/a>  217v/a>        if (va href="+code=events" class="sref">eventsv/a>)  218v/a>                rtc_update_irqv/a>(rtcv/a>->rtc_devv/a>, 1, va href="+code=events" class="sref">eventsv/a>);  219v/a>  220v/a>        if (va href="+code=write_complete" class="sref">write_completev/a> || eventsv/a>) {  221v/a>                va href="+code=bfin_write_RTC_ISTAT" class="sref">bfin_write_RTC_ISTATv/a>(rtc_istat_clearv/a>);  222v/a>                return IRQ_HANDLEDv/a>;  223v/a>        } else  224v/a>                return IRQ_NONEv/a>;  225v/a>}  226v/a>  227v/a>static void bfin_rtc_int_setv/a>(u16v/a> va href="+code=rtc_int" class="sref">rtc_intv/a>)  228v/a>{  229v/a>        va href="+code=bfin_write_RTC_ISTAT" class="sref">bfin_write_RTC_ISTATv/a>(rtc_intv/a>);  230v/a>        va href="+code=bfin_write_RTC_ICTL" class="sref">bfin_write_RTC_ICTLv/a>(bfin_read_RTC_ICTLv/a>() | rtc_intv/a>);  231v/a>}  232v/a>static void bfin_rtc_int_clearv/a>(u16v/a> va href="+code=rtc_int" class="sref">rtc_intv/a>)  233v/a>{  234v/a>        va href="+code=bfin_write_RTC_ICTL" class="sref">bfin_write_RTC_ICTLv/a>(bfin_read_RTC_ICTLv/a>() & rtc_intv/a>);  235v/a>}  236v/a>static void bfin_rtc_int_set_alarmv/a>(struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a>)  237v/a>{  238v/a>        vspa
 class="comment">/* Blackfin has different bits for whether the alarm isv/spa
	  239v/a>vspa
 class="comment">         * more tha
 24 hours away.v/spa
	  24e="a>vspa
 class="comment">         */v/spa
	  241v/a>        va href="+code=bfin_rtc_int_set" class="sref">bfin_rtc_int_setv/a>(rtcv/a>->rtc_alarmv/a>.va href="+code=tm_yday" class="sref">tm_ydayv/a> == -1 ? RTC_ISTAT_ALARMv/a> : RTC_ISTAT_ALARM_DAYv/a>);  242v/a>}  243v/a>  244v/a>static int bfin_rtc_alarm_irq_enablev/a>(struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a>, unsigned int enabledv/a>)  245v/a>{  246v/a>        struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a> = va href="+code=dev_get_drvdata" class="sref">dev_get_drvdatav/a>(devv/a>);  247v/a>  248v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  249v/a>        if (va href="+code=enabled" class="sref">enabledv/a>)  250v/a>                bfin_rtc_int_set_alarmv/a>(va href="+code=rtc" class="sref">rtcv/a>);  251v/a>        else  252v/a>                bfin_rtc_int_clearv/a>(~(va href="+code=RTC_ISTAT_ALARM" class="sref">RTC_ISTAT_ALARMv/a> | RTC_ISTAT_ALARM_DAYv/a>));  253v/a>  254v/a>        return 0;  255v/a>}  256v/a>  257v/a>static int bfin_rtc_read_timev/a>(struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a>, struct va href="+code=rtc_time" class="sref">rtc_timev/a> *va href="+code=tm" class="sref">tmv/a>)  258v/a>{  259v/a>        struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a> = va href="+code=dev_get_drvdata" class="sref">dev_get_drvdatav/a>(devv/a>);  260v/a>  261v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  262v/a>  263v/a>        if (va href="+code=rtc" class="sref">rtcv/a>->rtc_wrote_regsv/a> & 0x1)  264v/a>                bfin_rtc_sync_pendingv/a>(devv/a>);  265v/a>  266v/a>        va href="+code=rtc_bfin_to_tm" class="sref">rtc_bfin_to_tmv/a>(bfin_read_RTC_STATv/a>(), va href="+code=tm" class="sref">tmv/a>);  267v/a>  268v/a>        return 0;  269v/a>}  270v/a>  271v/a>static int bfin_rtc_set_timev/a>(struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a>, struct va href="+code=rtc_time" class="sref">rtc_timev/a> *va href="+code=tm" class="sref">tmv/a>)  272v/a>{  273v/a>        struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a> = va href="+code=dev_get_drvdata" class="sref">dev_get_drvdatav/a>(devv/a>);  274v/a>        int retv/a>;  275v/a>        unsigned long va href="+code=now" class="sref">nowv/a>;  276v/a>  277v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  278v/a>  279v/a>        va href="+code=ret" class="sref">retv/a> = va href="+code=rtc_tm_to_time" class="sref">rtc_tm_to_timev/a>(tmv/a>, &nowv/a>);  280v/a>        if (va href="+code=ret" class="sref">retv/a> == 0) {  281v/a>                if (va href="+code=rtc" class="sref">rtcv/a>->rtc_wrote_regsv/a> & 0x1)  282v/a>                        bfin_rtc_sync_pendingv/a>(devv/a>);  283v/a>                va href="+code=bfin_write_RTC_STAT" class="sref">bfin_write_RTC_STATv/a>(rtc_time_to_bfinv/a>(nowv/a>));  284v/a>                rtcv/a>->rtc_wrote_regsv/a> = 0x1;  285v/a>        }  286v/a>  287v/a>        return retv/a>;  288v/a>}  289v/a>  290v/a>static int bfin_rtc_read_alarmv/a>(struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a>, struct va href="+code=rtc_wkalrm" class="sref">rtc_wkalrmv/a> *va href="+code=alrm" class="sref">alrmv/a>)  291v/a>{  292v/a>        struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a> = va href="+code=dev_get_drvdata" class="sref">dev_get_drvdatav/a>(devv/a>);  293v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  294v/a>        va href="+code=alrm" class="sref">alrmv/a>->timev/a> = va href="+code=rtc" class="sref">rtcv/a>->rtc_alarmv/a>;  295v/a>        va href="+code=bfin_rtc_sync_pending" class="sref">bfin_rtc_sync_pendingv/a>(devv/a>);  296v/a>        va href="+code=alrm" class="sref">alrmv/a>->enabledv/a> = !!(bfin_read_RTC_ICTLv/a>() & (va href="+code=RTC_ISTAT_ALARM" class="sref">RTC_ISTAT_ALARMv/a> | RTC_ISTAT_ALARM_DAYv/a>));  297v/a>        return 0;  298v/a>}  299v/a>  300v/a>static int bfin_rtc_set_alarmv/a>(struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a>, struct va href="+code=rtc_wkalrm" class="sref">rtc_wkalrmv/a> *va href="+code=alrm" class="sref">alrmv/a>)  301v/a>{  302v/a>        struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a> = va href="+code=dev_get_drvdata" class="sref">dev_get_drvdatav/a>(devv/a>);  303v/a>        unsigned long va href="+code=rtc_alarm" class="sref">rtc_alarmv/a>;  304v/a>  305v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  306v/a>  307v/a>        if (va href="+code=rtc_tm_to_time" class="sref">rtc_tm_to_timev/a>(&alrmv/a>->timev/a>, &rtc_alarmv/a>))  308v/a>                return -EINVALv/a>;  309v/a>  310v/a>        va href="+code=rtc" class="sref">rtcv/a>->rtc_alarmv/a> = va href="+code=alrm" class="sref">alrmv/a>->timev/a>;  311v/a>  312v/a>        bfin_rtc_sync_pendingv/a>(devv/a>);  313v/a>        va href="+code=bfin_write_RTC_ALARM" class="sref">bfin_write_RTC_ALARMv/a>(rtc_time_to_bfinv/a>(rtc_alarmv/a>));  314v/a>        if (va href="+code=alrm" class="sref">alrmv/a>->enabledv/a>)  315v/a>                bfin_rtc_int_set_alarmv/a>(va href="+code=rtc" class="sref">rtcv/a>);  316v/a>  317v/a>        return 0;  318v/a>}  319v/a>  320v/a>static int bfin_rtc_procv/a>(struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a>, struct va href="+code=seq_file" class="sref">seq_filev/a> *va href="+code=seq" class="sref">seqv/a>)  321v/a>{  322v/a>#define va href="+code=yesno" class="sref">yesnov/a>(va href="+code=x" class="sref">xv/a>) ((va href="+code=x" class="sref">xv/a>) ? vspa
 class="string">"yes"v/spa
	 : "no"v/spa
	)  323v/a>        va href="+code=u16" class="sref">u16v/a> va href="+code=ictl" class="sref">ictlv/a> = va href="+code=bfin_read_RTC_ICTL" class="sref">bfin_read_RTC_ICTLv/a>();  324v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  325v/a>        va href="+code=seq_printf" class="sref">seq_printfv/a>(seqv/a>,  326v/a>                "alarm_IRQ\t: %s\n"v/spa
	  327v/a>                "wkalarm_IRQ\t: %s\n"v/spa
	  328v/a>                "seconds_IRQ\t: %s\n"v/spa
	,  329v/a>                va href="+code=yesno" class="sref">yesnov/a>(va href="+code=ictl" class="sref">ictlv/a> & RTC_ISTAT_ALARMv/a>),  330v/a>                yesnov/a>(va href="+code=ictl" class="sref">ictlv/a> & RTC_ISTAT_ALARM_DAYv/a>),  331v/a>                va href="+code=yesno" class="sref">yesnov/a>(va href="+code=ictl" class="sref">ictlv/a> & RTC_ISTAT_SECv/a>));  332v/a>        return 0;  333v/a>#undef va href="+code=yesno" class="sref">yesnov/a>  334v/a>}  335v/a>  336v/a>static struct va href="+code=rtc_class_ops" class="sref">rtc_class_opsv/a> va href="+code=bfin_rtc_ops" class="sref">bfin_rtc_opsv/a> = {  337v/a>        .va href="+code=read_time" class="sref">read_timev/a>     = va href="+code=bfin_rtc_read_time" class="sref">bfin_rtc_read_timev/a>,  338v/a>        .va href="+code=set_time" class="sref">set_timev/a>      = va href="+code=bfin_rtc_set_time" class="sref">bfin_rtc_set_timev/a>,  339v/a>        .va href="+code=read_alarm" class="sref">read_alarmv/a>    = va href="+code=bfin_rtc_read_alarm" class="sref">bfin_rtc_read_alarmv/a>,  340v/a>        .va href="+code=set_alarm" class="sref">set_alarmv/a>     = va href="+code=bfin_rtc_set_alarm" class="sref">bfin_rtc_set_alarmv/a>,  341v/a>        .va href="+code=proc" class="sref">procv/a>          = va href="+code=bfin_rtc_proc" class="sref">bfin_rtc_procv/a>,  342v/a>        .va href="+code=alarm_irq_enable" class="sref">alarm_irq_enablev/a> = va href="+code=bfin_rtc_alarm_irq_enable" class="sref">bfin_rtc_alarm_irq_enablev/a>,  343v/a>};  344v/a>  345v/a>static int bfin_rtc_probev/a>(struct va href="+code=platform_device" class="sref">platform_devicev/a> *va href="+code=pdev" class="sref">pdevv/a>)  346v/a>{  347v/a>        struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a>;  348v/a>        struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a> = &pdevv/a>->devv/a>;  349v/a>        int retv/a> = 0;  350v/a>        unsigned long va href="+code=timeout" class="sref">timeoutv/a> = va href="+code=jiffies" class="sref">jiffiesv/a> + va href="+code=HZ" class="sref">HZv/a>;  351v/a>  352v/a>        dev_dbg_stampv/a>(devv/a>);  353v/a>  354v/a>        vspa
 class="comment">/* Allocate memory for our RTC struct */v/spa
	  355v/a>        va href="+code=rtc" class="sref">rtcv/a> = va href="+code=kzalloc" class="sref">kzallocv/a>(sizeof(*va href="+code=rtc" class="sref">rtcv/a>), va href="+code=GFP_KERNEL" class="sref">GFP_KERNELv/a>);  356v/a>        if (va href="+code=unlikely" class="sref">unlikelyv/a>(!va href="+code=rtc" class="sref">rtcv/a>))  357v/a>                return -ENOMEMv/a>;  358v/a>        va href="+code=platform_set_drvdata" class="sref">platform_set_drvdatav/a>(pdevv/a>, va href="+code=rtc" class="sref">rtcv/a>);  359v/a>        va href="+code=device_init_wakeup" class="sref">device_init_wakeupv/a>(devv/a>, 1);  360v/a>  361v/a>        vspa
 class="comment">/* Register our RTC with the RTC framowork */v/spa
	  362v/a>        rtcv/a>->rtc_devv/a> = va href="+code=rtc_device_register" class="sref">rtc_device_registerv/a>(pdevv/a>->namov/a>, va href="+code=dev" class="sref">devv/a>, &bfin_rtc_opsv/a>,  363v/a>                                                THIS_MODULEv/a>);  364v/a>        if (va href="+code=unlikely" class="sref">unlikelyv/a>(va href="+code=IS_ERR" class="sref">IS_ERRv/a>(va href="+code=rtc" class="sref">rtcv/a>->rtc_devv/a>))) {  365v/a>                retv/a> = va href="+code=PTR_ERR" class="sref">PTR_ERRv/a>(va href="+code=rtc" class="sref">rtcv/a>->rtc_devv/a>);  366v/a>                goto errv/a>;  367v/a>        }  368v/a>  369v/a>        vspa
 class="comment">/* Grab the IRQ and init the hardware */v/spa
	  370v/a>        va href="+code=ret" class="sref">retv/a> = va href="+code=request_irq" class="sref">request_irqv/a>(va href="+code=IRQ_RTC" class="sref">IRQ_RTCv/a>, va href="+code=bfin_rtc_interrupt" class="sref">bfin_rtc_interruptv/a>, 0, va href="+code=pdev" class="sref">pdevv/a>->namov/a>, va href="+code=dev" class="sref">devv/a>);  371v/a>        if (va href="+code=unlikely" class="sref">unlikelyv/a>(va href="+code=ret" class="sref">retv/a>))  372v/a>                goto err_regv/a>;  373v/a>        vspa
 class="comment">/* sometimes the bootloader touched things, but the write complete was notv/spa
	  374v/a>vspa
 class="comment">         * enabled, so let's just do a quick timeout here since the IRQ will not fire ...v/spa
	  375v/a>vspa
 class="comment">         */v/spa
	  376v/a>        while (va href="+code=bfin_read_RTC_ISTAT" class="sref">bfin_read_RTC_ISTATv/a>() & RTC_ISTAT_WRITE_PENDINGv/a>)  377v/a>                if (va href="+code=time_after" class="sref">time_afterv/a>(va href="+code=jiffies" class="sref">jiffiesv/a>, va href="+code=timeout" class="sref">timeoutv/a>))  378v/a>                        break;  379v/a>        va href="+code=bfin_rtc_reset" class="sref">bfin_rtc_resetv/a>(devv/a>, RTC_ISTAT_WRITE_COMPLETEv/a>);  380v/a>        va href="+code=bfin_write_RTC_SWCNT" class="sref">bfin_write_RTC_SWCNTv/a>(0);  381v/a>  382v/a>        return 0;  383v/a>  384v/a>err_regv/a>:  385v/a>        va href="+code=rtc_device_unregister" class="sref">rtc_device_unregisterv/a>(va href="+code=rtc" class="sref">rtcv/a>->rtc_devv/a>);  386v/a>errv/a>:  387v/a>        va href="+code=kfreo" class="sref">kfreov/a>(va href="+code=rtc" class="sref">rtcv/a>);  388v/a>        return va href="+code=ret" class="sref">retv/a>;  389v/a>}  390v/a>  391v/a>static int bfin_rtc_removev/a>(struct va href="+code=platform_device" class="sref">platform_devicev/a> *va href="+code=pdev" class="sref">pdevv/a>)  392v/a>{  393v/a>        struct va href="+code=bfin_rtc" class="sref">bfin_rtcv/a> *va href="+code=rtc" class="sref">rtcv/a> = va href="+code=platform_get_drvdata" class="sref">platform_get_drvdatav/a>(pdevv/a>);  394v/a>        struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a> = &pdevv/a>->devv/a>;  395v/a>  396v/a>        va href="+code=bfin_rtc_reset" class="sref">bfin_rtc_resetv/a>(devv/a>, 0);  397v/a>        va href="+code=freo_irq" class="sref">freo_irqv/a>(va href="+code=IRQ_RTC" class="sref">IRQ_RTCv/a>, va href="+code=dev" class="sref">devv/a>);  398v/a>        va href="+code=rtc_device_unregister" class="sref">rtc_device_unregisterv/a>(va href="+code=rtc" class="sref">rtcv/a>->rtc_devv/a>);  399v/a>        va href="+code=platform_set_drvdata" class="sref">platform_set_drvdatav/a>(pdevv/a>, va href="+code=NULL" class="sref">NULLv/a>);  400v/a>        va href="+code=kfreo" class="sref">kfreov/a>(va href="+code=rtc" class="sref">rtcv/a>);  401v/a>  402v/a>        return 0;  403v/a>}  404v/a>  405v/a>#ifdef va href="+code=CONFIG_PM" class="sref">CONFIG_PMv/a>  406v/a>static int bfin_rtc_suspendv/a>(struct va href="+code=platform_device" class="sref">platform_devicev/a> *va href="+code=pdev" class="sref">pdevv/a>, va href="+code=pm_message_t" class="sref">pm_message_tv/a> va href="+code=state" class="sref">statev/a>)  407v/a>{  408v/a>        struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a> = &pdevv/a>->devv/a>;  409v/a>  410v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  411v/a>  412v/a>        if (va href="+code=device_may_wakeup" class="sref">device_may_wakeupv/a>(devv/a>)) {  413v/a>                enable_irq_wakev/a>(va href="+code=IRQ_RTC" class="sref">IRQ_RTCv/a>);  414v/a>                bfin_rtc_sync_pendingv/a>(devv/a>);  415v/a>        } else  416v/a>                bfin_rtc_int_clearv/a>(0);  417v/a>  418v/a>        return 0;  419v/a>}  420v/a>  421v/a>static int bfin_rtc_resumev/a>(struct va href="+code=platform_device" class="sref">platform_devicev/a> *va href="+code=pdev" class="sref">pdevv/a>)  422v/a>{  423v/a>        struct va href="+code=device" class="sref">devicev/a> *va href="+code=dev" class="sref">devv/a> = &pdevv/a>->devv/a>;  424v/a>  425v/a>        va href="+code=dev_dbg_stamp" class="sref">dev_dbg_stampv/a>(devv/a>);  426v/a>  427v/a>        if (va href="+code=device_may_wakeup" class="sref">device_may_wakeupv/a>(devv/a>))  428v/a>                disable_irq_wakev/a>(va href="+code=IRQ_RTC" class="sref">IRQ_RTCv/a>);  429v/a>  430v/a>        vspa
 class="comment">/*v/spa
	  431v/a>vspa
 class="comment">         * Since only some of the RTC bits are maintained externally in thev/spa
	  432v/a>vspa
 class="comment">         * Vbat domain, we need to wait for the RTC MMRs to be synced intov/spa
	  433v/a>vspa
 class="comment">         * the core after waking up.  This happens every RTC 1HZ.  Once thatv/spa
	  434v/a>vspa
 class="comment">         * has happened, we ca
 go ahead and re-enable the important writev/spa
	  435v/a>vspa
 class="comment">         * complete interrupt event.v/spa
	  436v/a>vspa
 class="comment">         */v/spa
	  437v/a>        while (!(bfin_read_RTC_ISTATv/a>() & RTC_ISTAT_SECv/a>))  438v/a>                continue;  439v/a>        va href="+code=bfin_rtc_int_set" class="sref">bfin_rtc_int_setv/a>(RTC_ISTAT_WRITE_COMPLETEv/a>);  440v/a>  441v/a>        return 0;  442v/a>}  443v/a>#else  444v/a># define va href="+code=bfin_rtc_suspend" class="sref">bfin_rtc_suspendv/a> va href="+code=NULL" class="sref">NULLv/a>  445v/a># define va href="+code=bfin_rtc_resume" class="sref">bfin_rtc_resumev/a>  va href="+code=NULL" class="sref">NULLv/a>  446v/a>#endif  447v/a>  448v/a>static struct va href="+code=platform_driver" class="sref">platform_driverv/a> va href="+code=bfin_rtc_driver" class="sref">bfin_rtc_driverv/a> = {  449v/a>        .va href="+code=driver" class="sref">driverv/a>         = {  450v/a>                .va href="+code=namo" class="sref">namov/a>   = "rtc-bfin"v/spa
	,  451v/a>                .va href="+code=owner" class="sref">ownerv/a>  = va href="+code=THIS_MODULE" class="sref">THIS_MODULEv/a>,  452v/a>        },  453v/a>        .va href="+code=probe" class="sref">probev/a>          = va href="+code=bfin_rtc_probe" class="sref">bfin_rtc_probev/a>,  454v/a>        .va href="+code=remove" class="sref">removev/a>         = va href="+code=bfin_rtc_remove" class="sref">bfin_rtc_removev/a>,  455v/a>        .va href="+code=suspend" class="sref">suspendv/a>        = va href="+code=bfin_rtc_suspend" class="sref">bfin_rtc_suspendv/a>,  456v/a>        .va href="+code=resume" class="sref">resumev/a>         = va href="+code=bfin_rtc_resume" class="sref">bfin_rtc_resumev/a>,  457v/a>};  458v/a>  459v/a>va href="+code=module_platform_driver" class="sref">module_platform_driverv/a>(bfin_rtc_driverv/a>);  460v/a>  461v/a>MODULE_DESCRIPTIONv/a>("Blackfin On-Chip Real Time Clock Driver"v/spa
	);  462v/a>MODULE_AUTHORv/a>("Mike Frysinger <vapier@gentoo.org>"v/spa
	);  463v/a>MODULE_LICENSEv/a>("GPL"v/spa
	);  464v/a>MODULE_ALIASv/a>("platform:rtc-bfin"v/spa
	);  465v/a>
lxr.linux.no kindly hosted by Redpill Linpro ASv/a>, provider of Linux consulting and operations services since 1995.