Пример #1
0
static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
	unsigned status;
	unsigned long sl_irq_flags;
	int ret;

	spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags);
	if(tegra_rtc_check_busy()) { /* wait for the busy bit to clear. */
		spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags);
		ret = tegra_rtc_wait_while_busy(dev);
		if (ret)
			return ret;
		spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags);
	}
	/* read the original value, and OR in the flag. */
	status = tegra_rtc_read(RTC_TEGRA_REG_INTR_MASK);
	if (enabled)
		status |= RTC_TEGRA_INTR_MASK_SEC_ALARM0; /* set it */
	else
		status &= ~RTC_TEGRA_INTR_MASK_SEC_ALARM0; /* clear it */
	tegra_rtc_write(RTC_TEGRA_REG_INTR_MASK, status);
	spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags);

	return 0;
}
Пример #2
0
static irqreturn_t tegra_rtc_irq_handler(int irq, void *data)
{
	struct device *dev = data;
	struct tegra_rtc_info *info = dev_get_drvdata(dev);
	unsigned long events = 0;
	unsigned status;
	unsigned long sl_irq_flags;

	status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
	if (status) {
		/* clear the interrupt masks and status on any irq. */
		tegra_rtc_wait_while_busy(dev);
		spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
		writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
		writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
		spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
	}

	/* check if Alarm */
	if ((status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0))
		events |= RTC_IRQF | RTC_AF;

	/* check if Periodic */
	if ((status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM))
		events |= RTC_IRQF | RTC_PF;

	rtc_update_irq(info->rtc_dev, 1, events);

	return IRQ_HANDLED;
}
Пример #3
0
static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
	struct tegra_rtc_info *info = dev_get_drvdata(dev);
	unsigned long sec;

	if (alarm->enabled)
		rtc_tm_to_time(&alarm->time, &sec);
	else
		sec = 0;

	tegra_rtc_wait_while_busy(dev);
	writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
	dev_vdbg(dev, "alarm read back as %d\n",
		readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));

	/* if successfully written and alarm is enabled ... */
	if (sec) {
		tegra_rtc_alarm_irq_enable(dev, 1);

		dev_vdbg(dev, "alarm set as %lu. %d/%d/%d %d:%02u:%02u\n",
			sec,
			alarm->time.tm_mon+1,
			alarm->time.tm_mday,
			alarm->time.tm_year+1900,
			alarm->time.tm_hour,
			alarm->time.tm_min,
			alarm->time.tm_sec);
	} else {
		/* disable alarm if 0 or write error. */
		dev_vdbg(dev, "alarm disabled\n");
		tegra_rtc_alarm_irq_enable(dev, 0);
	}

	return 0;
}
Пример #4
0
static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	struct tegra_rtc_info *info = dev_get_drvdata(dev);
	unsigned long sec;
	int ret;

	/* convert tm to seconds. */
	ret = rtc_valid_tm(tm);
	if (ret)
		return ret;

	rtc_tm_to_time(tm, &sec);

	dev_vdbg(dev, "time set to %lu. %d/%d/%d %d:%02u:%02u\n",
		sec,
		tm->tm_mon+1,
		tm->tm_mday,
		tm->tm_year+1900,
		tm->tm_hour,
		tm->tm_min,
		tm->tm_sec
	);

	/* seconds only written if wait succeeded. */
	ret = tegra_rtc_wait_while_busy(dev);
	if (!ret)
		writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS);

	dev_vdbg(dev, "time read back as %d\n",
		readl(info->rtc_base + TEGRA_RTC_REG_SECONDS));

	return ret;
}
void tegra_rtc_set_trigger(unsigned long cycles)
{
	unsigned long msec;

	/* Convert to msec */
	msec = cycles / 1000;

	if (msec)
		msec = 0x80000000 | (0x0fffffff & msec);

	tegra_rtc_wait_while_busy();

	writel(msec, rtc_base + TEGRA_RTC_REG_MSEC_CDN_ALARM0);

	tegra_rtc_wait_while_busy();

	if (msec)
		tegra_rtc_alarm_irq_enable(1);
	else
		tegra_rtc_alarm_irq_enable(0);
}
Пример #6
0
/* waits for the RTC to not be busy accessing APB, then write a single value. */
static int tegra_rtc_write_not_busy(struct device *dev, unsigned ofs, u32 value)
{
	unsigned long sl_irq_flags;
	int ret;
	spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags);
	if(tegra_rtc_check_busy()) {
		spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags);
		ret = tegra_rtc_wait_while_busy(dev);
		if (ret)
			return ret;
		spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags);
	}
	tegra_rtc_write(ofs, value);
	spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags);
	return 0;
}
static irqreturn_t tegra_rtc_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *evt = (struct clock_event_device *)dev_id;
	u32 status;

	status = readl(rtc_base + TEGRA_RTC_REG_INTR_STATUS);
	if (status) {
		/* clear the interrupt masks and status on any irq. */
		tegra_rtc_wait_while_busy();
		writel(0, rtc_base + TEGRA_RTC_REG_INTR_MASK);
		writel(status, rtc_base + TEGRA_RTC_REG_INTR_STATUS);
	}

	if ((status & TEGRA_RTC_INTR_STATUS_MSEC_CDN_ALARM))
		evt->event_handler(evt);

	return IRQ_HANDLED;
}
Пример #8
0
static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
	struct tegra_rtc_info *info = dev_get_drvdata(dev);
	unsigned status;
	unsigned long sl_irq_flags;

	tegra_rtc_wait_while_busy(dev);
	spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);

	/* read the original value, and OR in the flag. */
	status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
	if (enabled)
		status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */
	else
		status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */

	writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);

	spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);

	return 0;
}
Пример #9
0
static int tegra_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
	struct device *dev = &pdev->dev;
	struct tegra_rtc_info *info = platform_get_drvdata(pdev);

	tegra_rtc_wait_while_busy(dev);

	/* only use ALARM0 as a wake source. */
	writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
	writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0,
		info->rtc_base + TEGRA_RTC_REG_INTR_MASK);

	dev_vdbg(dev, "alarm sec = %d\n",
		readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));

	dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n",
		device_may_wakeup(dev), info->tegra_rtc_irq);

	/* leave the alarms on as a wake source. */
	if (device_may_wakeup(dev))
		enable_irq_wake(info->tegra_rtc_irq);

	return 0;
}