1031 lines · 26.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+/* * TI OMAP Real Time Clock interface for Linux * * Copyright (C) 2003 MontaVista Software, Inc. * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com> * * Copyright (C) 2006 David Brownell (new RTC framework) * Copyright (C) 2014 Johan Hovold <johan@kernel.org> */ #include <linux/bcd.h>#include <linux/clk.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/io.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/of.h>#include <linux/pinctrl/pinctrl.h>#include <linux/pinctrl/pinconf.h>#include <linux/pinctrl/pinconf-generic.h>#include <linux/platform_device.h>#include <linux/pm_runtime.h>#include <linux/property.h>#include <linux/rtc.h>#include <linux/rtc/rtc-omap.h> /* * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock * with century-range alarm matching, driven by the 32kHz clock. * * The main user-visible ways it differs from PC RTCs are by omitting * "don't care" alarm fields and sub-second periodic IRQs, and having * an autoadjust mechanism to calibrate to the true oscillator rate. * * Board-specific wiring options include using split power mode with * RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset), * and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from * low power modes) for OMAP1 boards (OMAP-L138 has this built into * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment. */ /* RTC registers */#define OMAP_RTC_SECONDS_REG		0x00#define OMAP_RTC_MINUTES_REG		0x04#define OMAP_RTC_HOURS_REG		0x08#define OMAP_RTC_DAYS_REG		0x0C#define OMAP_RTC_MONTHS_REG		0x10#define OMAP_RTC_YEARS_REG		0x14#define OMAP_RTC_WEEKS_REG		0x18 #define OMAP_RTC_ALARM_SECONDS_REG	0x20#define OMAP_RTC_ALARM_MINUTES_REG	0x24#define OMAP_RTC_ALARM_HOURS_REG	0x28#define OMAP_RTC_ALARM_DAYS_REG		0x2c#define OMAP_RTC_ALARM_MONTHS_REG	0x30#define OMAP_RTC_ALARM_YEARS_REG	0x34 #define OMAP_RTC_CTRL_REG		0x40#define OMAP_RTC_STATUS_REG		0x44#define OMAP_RTC_INTERRUPTS_REG		0x48 #define OMAP_RTC_COMP_LSB_REG		0x4c#define OMAP_RTC_COMP_MSB_REG		0x50#define OMAP_RTC_OSC_REG		0x54 #define OMAP_RTC_SCRATCH0_REG		0x60#define OMAP_RTC_SCRATCH1_REG		0x64#define OMAP_RTC_SCRATCH2_REG		0x68 #define OMAP_RTC_KICK0_REG		0x6c#define OMAP_RTC_KICK1_REG		0x70 #define OMAP_RTC_IRQWAKEEN		0x7c #define OMAP_RTC_ALARM2_SECONDS_REG	0x80#define OMAP_RTC_ALARM2_MINUTES_REG	0x84#define OMAP_RTC_ALARM2_HOURS_REG	0x88#define OMAP_RTC_ALARM2_DAYS_REG	0x8c#define OMAP_RTC_ALARM2_MONTHS_REG	0x90#define OMAP_RTC_ALARM2_YEARS_REG	0x94 #define OMAP_RTC_PMIC_REG		0x98 /* OMAP_RTC_CTRL_REG bit fields: */#define OMAP_RTC_CTRL_SPLIT		BIT(7)#define OMAP_RTC_CTRL_DISABLE		BIT(6)#define OMAP_RTC_CTRL_SET_32_COUNTER	BIT(5)#define OMAP_RTC_CTRL_TEST		BIT(4)#define OMAP_RTC_CTRL_MODE_12_24	BIT(3)#define OMAP_RTC_CTRL_AUTO_COMP		BIT(2)#define OMAP_RTC_CTRL_ROUND_30S		BIT(1)#define OMAP_RTC_CTRL_STOP		BIT(0) /* OMAP_RTC_STATUS_REG bit fields: */#define OMAP_RTC_STATUS_POWER_UP	BIT(7)#define OMAP_RTC_STATUS_ALARM2		BIT(7)#define OMAP_RTC_STATUS_ALARM		BIT(6)#define OMAP_RTC_STATUS_1D_EVENT	BIT(5)#define OMAP_RTC_STATUS_1H_EVENT	BIT(4)#define OMAP_RTC_STATUS_1M_EVENT	BIT(3)#define OMAP_RTC_STATUS_1S_EVENT	BIT(2)#define OMAP_RTC_STATUS_RUN		BIT(1)#define OMAP_RTC_STATUS_BUSY		BIT(0) /* OMAP_RTC_INTERRUPTS_REG bit fields: */#define OMAP_RTC_INTERRUPTS_IT_ALARM2	BIT(4)#define OMAP_RTC_INTERRUPTS_IT_ALARM	BIT(3)#define OMAP_RTC_INTERRUPTS_IT_TIMER	BIT(2) /* OMAP_RTC_OSC_REG bit fields: */#define OMAP_RTC_OSC_32KCLK_EN		BIT(6)#define OMAP_RTC_OSC_SEL_32KCLK_SRC	BIT(3)#define OMAP_RTC_OSC_OSC32K_GZ_DISABLE	BIT(4) /* OMAP_RTC_IRQWAKEEN bit fields: */#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN	BIT(1) /* OMAP_RTC_PMIC bit fields: */#define OMAP_RTC_PMIC_POWER_EN_EN	BIT(16)#define OMAP_RTC_PMIC_EXT_WKUP_EN(x)	BIT(x)#define OMAP_RTC_PMIC_EXT_WKUP_POL(x)	BIT(4 + x) /* OMAP_RTC_KICKER values */#define	KICK0_VALUE			0x83e70b13#define	KICK1_VALUE			0x95a4f1e0 struct omap_rtc; struct omap_rtc_device_type {	bool has_32kclk_en;	bool has_irqwakeen;	bool has_pmic_mode;	bool has_power_up_reset;	void (*lock)(struct omap_rtc *rtc);	void (*unlock)(struct omap_rtc *rtc);}; struct omap_rtc {	struct rtc_device *rtc;	void __iomem *base;	struct clk *clk;	int irq_alarm;	int irq_timer;	u8 interrupts_reg;	bool is_pmic_controller;	bool has_ext_clk;	bool is_suspending;	const struct omap_rtc_device_type *type;	struct pinctrl_dev *pctldev;}; static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg){	return readb(rtc->base + reg);} static inline u32 rtc_readl(struct omap_rtc *rtc, unsigned int reg){	return readl(rtc->base + reg);} static inline void rtc_write(struct omap_rtc *rtc, unsigned int reg, u8 val){	writeb(val, rtc->base + reg);} static inline void rtc_writel(struct omap_rtc *rtc, unsigned int reg, u32 val){	writel(val, rtc->base + reg);} static void am3352_rtc_unlock(struct omap_rtc *rtc){	rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE);	rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE);} static void am3352_rtc_lock(struct omap_rtc *rtc){	rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0);	rtc_writel(rtc, OMAP_RTC_KICK1_REG, 0);} static void default_rtc_unlock(struct omap_rtc *rtc){} static void default_rtc_lock(struct omap_rtc *rtc){} /* * We rely on the rtc framework to handle locking (rtc->ops_lock), * so the only other requirement is that register accesses which * require BUSY to be clear are made with IRQs locally disabled */static void rtc_wait_not_busy(struct omap_rtc *rtc){	int count;	u8 status; 	/* BUSY may stay active for 1/32768 second (~30 usec) */	for (count = 0; count < 50; count++) {		status = rtc_read(rtc, OMAP_RTC_STATUS_REG);		if (!(status & OMAP_RTC_STATUS_BUSY))			break;		udelay(1);	}	/* now we have ~15 usec to read/write various registers */} static irqreturn_t rtc_irq(int irq, void *dev_id){	struct omap_rtc	*rtc = dev_id;	unsigned long events = 0;	u8 irq_data; 	irq_data = rtc_read(rtc, OMAP_RTC_STATUS_REG); 	/* alarm irq? */	if (irq_data & OMAP_RTC_STATUS_ALARM) {		rtc->type->unlock(rtc);		rtc_write(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM);		rtc->type->lock(rtc);		events |= RTC_IRQF | RTC_AF;	} 	/* 1/sec periodic/update irq? */	if (irq_data & OMAP_RTC_STATUS_1S_EVENT)		events |= RTC_IRQF | RTC_UF; 	rtc_update_irq(rtc->rtc, 1, events); 	return IRQ_HANDLED;} static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled){	struct omap_rtc *rtc = dev_get_drvdata(dev);	u8 reg, irqwake_reg = 0; 	local_irq_disable();	rtc_wait_not_busy(rtc);	reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);	if (rtc->type->has_irqwakeen)		irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN); 	if (enabled) {		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;		irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;	} else {		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;		irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;	}	rtc_wait_not_busy(rtc);	rtc->type->unlock(rtc);	rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);	if (rtc->type->has_irqwakeen)		rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);	rtc->type->lock(rtc);	local_irq_enable(); 	return 0;} /* this hardware doesn't support "don't care" alarm fields */static void tm2bcd(struct rtc_time *tm){	tm->tm_sec = bin2bcd(tm->tm_sec);	tm->tm_min = bin2bcd(tm->tm_min);	tm->tm_hour = bin2bcd(tm->tm_hour);	tm->tm_mday = bin2bcd(tm->tm_mday); 	tm->tm_mon = bin2bcd(tm->tm_mon + 1);	tm->tm_year = bin2bcd(tm->tm_year - 100);} static void bcd2tm(struct rtc_time *tm){	tm->tm_sec = bcd2bin(tm->tm_sec);	tm->tm_min = bcd2bin(tm->tm_min);	tm->tm_hour = bcd2bin(tm->tm_hour);	tm->tm_mday = bcd2bin(tm->tm_mday);	tm->tm_mon = bcd2bin(tm->tm_mon) - 1;	/* epoch == 1900 */	tm->tm_year = bcd2bin(tm->tm_year) + 100;} static void omap_rtc_read_time_raw(struct omap_rtc *rtc, struct rtc_time *tm){	tm->tm_sec = rtc_read(rtc, OMAP_RTC_SECONDS_REG);	tm->tm_min = rtc_read(rtc, OMAP_RTC_MINUTES_REG);	tm->tm_hour = rtc_read(rtc, OMAP_RTC_HOURS_REG);	tm->tm_mday = rtc_read(rtc, OMAP_RTC_DAYS_REG);	tm->tm_mon = rtc_read(rtc, OMAP_RTC_MONTHS_REG);	tm->tm_year = rtc_read(rtc, OMAP_RTC_YEARS_REG);} static int omap_rtc_read_time(struct device *dev, struct rtc_time *tm){	struct omap_rtc *rtc = dev_get_drvdata(dev); 	/* we don't report wday/yday/isdst ... */	local_irq_disable();	rtc_wait_not_busy(rtc);	omap_rtc_read_time_raw(rtc, tm);	local_irq_enable(); 	bcd2tm(tm); 	return 0;} static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm){	struct omap_rtc *rtc = dev_get_drvdata(dev); 	tm2bcd(tm); 	local_irq_disable();	rtc_wait_not_busy(rtc); 	rtc->type->unlock(rtc);	rtc_write(rtc, OMAP_RTC_YEARS_REG, tm->tm_year);	rtc_write(rtc, OMAP_RTC_MONTHS_REG, tm->tm_mon);	rtc_write(rtc, OMAP_RTC_DAYS_REG, tm->tm_mday);	rtc_write(rtc, OMAP_RTC_HOURS_REG, tm->tm_hour);	rtc_write(rtc, OMAP_RTC_MINUTES_REG, tm->tm_min);	rtc_write(rtc, OMAP_RTC_SECONDS_REG, tm->tm_sec);	rtc->type->lock(rtc); 	local_irq_enable(); 	return 0;} static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm){	struct omap_rtc *rtc = dev_get_drvdata(dev);	u8 interrupts; 	local_irq_disable();	rtc_wait_not_busy(rtc); 	alm->time.tm_sec = rtc_read(rtc, OMAP_RTC_ALARM_SECONDS_REG);	alm->time.tm_min = rtc_read(rtc, OMAP_RTC_ALARM_MINUTES_REG);	alm->time.tm_hour = rtc_read(rtc, OMAP_RTC_ALARM_HOURS_REG);	alm->time.tm_mday = rtc_read(rtc, OMAP_RTC_ALARM_DAYS_REG);	alm->time.tm_mon = rtc_read(rtc, OMAP_RTC_ALARM_MONTHS_REG);	alm->time.tm_year = rtc_read(rtc, OMAP_RTC_ALARM_YEARS_REG); 	local_irq_enable(); 	bcd2tm(&alm->time); 	interrupts = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);	alm->enabled = !!(interrupts & OMAP_RTC_INTERRUPTS_IT_ALARM); 	return 0;} static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm){	struct omap_rtc *rtc = dev_get_drvdata(dev);	u8 reg, irqwake_reg = 0; 	tm2bcd(&alm->time); 	local_irq_disable();	rtc_wait_not_busy(rtc); 	rtc->type->unlock(rtc);	rtc_write(rtc, OMAP_RTC_ALARM_YEARS_REG, alm->time.tm_year);	rtc_write(rtc, OMAP_RTC_ALARM_MONTHS_REG, alm->time.tm_mon);	rtc_write(rtc, OMAP_RTC_ALARM_DAYS_REG, alm->time.tm_mday);	rtc_write(rtc, OMAP_RTC_ALARM_HOURS_REG, alm->time.tm_hour);	rtc_write(rtc, OMAP_RTC_ALARM_MINUTES_REG, alm->time.tm_min);	rtc_write(rtc, OMAP_RTC_ALARM_SECONDS_REG, alm->time.tm_sec); 	reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);	if (rtc->type->has_irqwakeen)		irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN); 	if (alm->enabled) {		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;		irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;	} else {		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;		irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;	}	rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);	if (rtc->type->has_irqwakeen)		rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);	rtc->type->lock(rtc); 	local_irq_enable(); 	return 0;} static struct omap_rtc *omap_rtc_power_off_rtc; /** * omap_rtc_power_off_program: Set the pmic power off sequence. The RTC * generates pmic_pwr_enable control, which can be used to control an external * PMIC. */int omap_rtc_power_off_program(struct device *dev){	struct omap_rtc *rtc = omap_rtc_power_off_rtc;	struct rtc_time tm;	unsigned long now;	int seconds;	u32 val; 	rtc->type->unlock(rtc);	/* enable pmic_power_en control */	val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);	rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); again:	/* Clear any existing ALARM2 event */	rtc_writel(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM2); 	/* set alarm one second from now */	omap_rtc_read_time_raw(rtc, &tm);	seconds = tm.tm_sec;	bcd2tm(&tm);	now = rtc_tm_to_time64(&tm);	rtc_time64_to_tm(now + 1, &tm); 	tm2bcd(&tm); 	rtc_wait_not_busy(rtc); 	rtc_write(rtc, OMAP_RTC_ALARM2_SECONDS_REG, tm.tm_sec);	rtc_write(rtc, OMAP_RTC_ALARM2_MINUTES_REG, tm.tm_min);	rtc_write(rtc, OMAP_RTC_ALARM2_HOURS_REG, tm.tm_hour);	rtc_write(rtc, OMAP_RTC_ALARM2_DAYS_REG, tm.tm_mday);	rtc_write(rtc, OMAP_RTC_ALARM2_MONTHS_REG, tm.tm_mon);	rtc_write(rtc, OMAP_RTC_ALARM2_YEARS_REG, tm.tm_year); 	/*	 * enable ALARM2 interrupt	 *	 * NOTE: this fails on AM3352 if rtc_write (writeb) is used	 */	val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);	rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG,			val | OMAP_RTC_INTERRUPTS_IT_ALARM2); 	/* Retry in case roll over happened before alarm was armed. */	if (rtc_read(rtc, OMAP_RTC_SECONDS_REG) != seconds) {		val = rtc_read(rtc, OMAP_RTC_STATUS_REG);		if (!(val & OMAP_RTC_STATUS_ALARM2))			goto again;	} 	rtc->type->lock(rtc); 	return 0;}EXPORT_SYMBOL(omap_rtc_power_off_program); /* * omap_rtc_poweroff: RTC-controlled power off * * The RTC can be used to control an external PMIC via the pmic_power_en pin, * which can be configured to transition to OFF on ALARM2 events. * * Notes: * The one-second alarm offset is the shortest offset possible as the alarm * registers must be set before the next timer update and the offset * calculation is too heavy for everything to be done within a single access * period (~15 us). * * Called with local interrupts disabled. */static void omap_rtc_power_off(void){	struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc;	u32 val; 	omap_rtc_power_off_program(rtc->dev.parent); 	/* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */	omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc);	val = rtc_readl(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG);	val |= OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL(0) |			OMAP_RTC_PMIC_EXT_WKUP_EN(0);	rtc_writel(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG, val);	omap_rtc_power_off_rtc->type->lock(omap_rtc_power_off_rtc); 	/*	 * Wait for alarm to trigger (within one second) and external PMIC to	 * power off the system. Add a 500 ms margin for external latencies	 * (e.g. debounce circuits).

Lines 1–500 of 1031.