Ejemplo n.º 1
0
static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
	void __iomem *ioaddr = pdata->ioaddr;
	u32 lp_cr;
	unsigned long lock_flags = 0;

	spin_lock_irqsave(&rtc_lock, lock_flags);

	if (enable) {
		if (!pdata->irq_enable) {
			enable_irq(pdata->irq);
			pdata->irq_enable = true;
		}
		lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
		lp_cr |= SRTC_LPCR_ALP | SRTC_LPCR_WAE;
		__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
	} else {
		lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
		if (((lp_cr & SRTC_LPCR_ALL_INT_EN) == 0)
		    && (pdata->irq_enable)) {
			disable_irq(pdata->irq);
			pdata->irq_enable = false;
		}
		__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
	}

	rtc_write_sync_lp(ioaddr);
	spin_unlock_irqrestore(&rtc_lock, lock_flags);
	return 0;
}
Ejemplo n.º 2
0
/*!
 * This function sets the internal RTC time based on tm in Gregorian date.
 *
 * @param  tm           the time value to be set in the RTC
 *
 * @return  0 if successful; non-zero otherwise.
 */
static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
	void __iomem *ioaddr = pdata->ioaddr;
	unsigned long time;
	u64 old_time_47bit, new_time_47bit;
	int ret;
	ret = rtc_tm_to_time(tm, &time);
	if (ret != 0)
		return ret;

	old_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
			((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
	old_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;

	__raw_writel(time, ioaddr + SRTC_LPSCMR);
	rtc_write_sync_lp(ioaddr);

	new_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
			((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
	new_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;

	/* update the difference between previous time and new time */
	time_diff = new_time_47bit - old_time_47bit;

	/* signal all waiting threads that time changed */
	complete_all(&srtc_completion);
	/* reinitialize completion variable */
	INIT_COMPLETION(srtc_completion);

	return 0;
}
Ejemplo n.º 3
0
/*!
 * This function sets the internal RTC time based on tm in Gregorian date.
 *
 * @param  tm           the time value to be set in the RTC
 *
 * @return  0 if successful; non-zero otherwise.
 */
static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
	void __iomem *ioaddr = pdata->ioaddr;
	unsigned long time;
	int ret;
	ret = rtc_tm_to_time(tm, &time);
	if (ret != 0)
		return ret;

	__raw_writel(time, ioaddr + SRTC_LPSCMR);
	rtc_write_sync_lp(ioaddr);

	return 0;
}
Ejemplo n.º 4
0
/*!
 * This function sets the RTC alarm based on passed in alrm.
 *
 * @param  alrm         the alarm value to be set in the RTC
 *
 * @return  0 if successful; non-zero otherwise.
 */
static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
	void __iomem *ioaddr = pdata->ioaddr;
	unsigned long lock_flags = 0;
	u32 lp_cr;
	int ret;

	if (rtc_valid_tm(&alrm->time)) {
		if (alrm->time.tm_sec > 59 ||
		    alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) {
			return -EINVAL;
		}
	}

	spin_lock_irqsave(&rtc_lock, lock_flags);
	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);

	ret = rtc_update_alarm(dev, &alrm->time);
	if (ret)
		goto out;

	if (alrm->enabled)
		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
	else
		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);

	if (lp_cr & SRTC_LPCR_ALL_INT_EN) {
		if (!pdata->irq_enable) {
			enable_irq(pdata->irq);
			pdata->irq_enable = true;
		}
	} else {
		if (pdata->irq_enable) {
			disable_irq(pdata->irq);
			pdata->irq_enable = false;
		}
	}

	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);

out:
	spin_unlock_irqrestore(&rtc_lock, lock_flags);
	rtc_write_sync_lp(ioaddr);
	return ret;
}
Ejemplo n.º 5
0
int rtc_internal_set(u32 time){

	int ret;
        u32 lp_cr;
        u64 old_time_47bit, new_time_47bit;
#ifdef DEBUG_RTC
	printf("\nSetting time to iMX6...");
#endif
        old_time_47bit = (((u64) (__raw_readl(SNVS_BASE_ADDR + SNVS_LPSRTCMR) &
                ((0x1 << CNTR_TO_SECS_SH) - 1)) << 32) |
                ((u64) __raw_readl(SNVS_BASE_ADDR + SNVS_LPSRTCLR)));

        /* Disable RTC first */
        lp_cr = __raw_readl(SNVS_BASE_ADDR + SNVS_LPCR) & ~SNVS_LPCR_SRTC_ENV;
        __raw_writel(lp_cr,SNVS_BASE_ADDR + SNVS_LPCR);
        while (__raw_readl(SNVS_BASE_ADDR + SNVS_LPCR) & SNVS_LPCR_SRTC_ENV)
                ;

        /* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */
        __raw_writel(time << CNTR_TO_SECS_SH, SNVS_BASE_ADDR + SNVS_LPSRTCLR);
        __raw_writel(time >> (32 - CNTR_TO_SECS_SH), SNVS_BASE_ADDR + SNVS_LPSRTCMR);

        /* Enable RTC again */
        __raw_writel(lp_cr | SNVS_LPCR_SRTC_ENV, SNVS_BASE_ADDR + SNVS_LPCR);
        while (!(__raw_readl(SNVS_BASE_ADDR + SNVS_LPCR) & SNVS_LPCR_SRTC_ENV))
                ;

        rtc_write_sync_lp();

        new_time_47bit = (((u64) (__raw_readl(SNVS_BASE_ADDR + SNVS_LPSRTCMR) &
                ((0x1 << CNTR_TO_SECS_SH) - 1)) << 32) |
                ((u64) __raw_readl(SNVS_BASE_ADDR + SNVS_LPSRTCLR)));
#ifdef DEBUG_RTC
       	printf("Done!\n"); 
#endif
	return 0;
}
Ejemplo n.º 6
0
/*!
 * This function is the RTC interrupt service routine.
 *
 * @param  irq          RTC IRQ number
 * @param  dev_id       device ID which is not used
 *
 * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
 */
static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
{
	struct platform_device *pdev = dev_id;
	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
	void __iomem *ioaddr = pdata->ioaddr;
	u32 lp_status, lp_cr;
	u32 events = 0;

	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);

	/* update irq data & counter */
	if (lp_status & SRTC_LPSR_ALP) {
		if (lp_cr & SRTC_LPCR_ALP)
			events |= (RTC_AF | RTC_IRQF);

		/* disable further lp alarm interrupts */
		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
	}

	/* Update interrupt enables */
	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);

	/* If no interrupts are enabled, turn off interrupts in kernel */
	if (((lp_cr & SRTC_LPCR_ALL_INT_EN) == 0) && (pdata->irq_enable)) {
		disable_irq_nosync(pdata->irq);
		pdata->irq_enable = false;
	}

	/* clear interrupt status */
	__raw_writel(lp_status, ioaddr + SRTC_LPSR);

	rtc_write_sync_lp(ioaddr);
	rtc_update_irq(pdata->rtc, 1, events);
	return IRQ_HANDLED;
}