18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * TI OMAP Real Time Clock interface for Linux
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2003 MontaVista Software, Inc.
68c2ecf20Sopenharmony_ci * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 2006 David Brownell (new RTC framework)
98c2ecf20Sopenharmony_ci * Copyright (C) 2014 Johan Hovold <johan@kernel.org>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/bcd.h>
138c2ecf20Sopenharmony_ci#include <linux/clk.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci#include <linux/ioport.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/of.h>
218c2ecf20Sopenharmony_ci#include <linux/of_device.h>
228c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
238c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
248c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
258c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
268c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
278c2ecf20Sopenharmony_ci#include <linux/rtc.h>
288c2ecf20Sopenharmony_ci#include <linux/rtc/rtc-omap.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/*
318c2ecf20Sopenharmony_ci * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock
328c2ecf20Sopenharmony_ci * with century-range alarm matching, driven by the 32kHz clock.
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * The main user-visible ways it differs from PC RTCs are by omitting
358c2ecf20Sopenharmony_ci * "don't care" alarm fields and sub-second periodic IRQs, and having
368c2ecf20Sopenharmony_ci * an autoadjust mechanism to calibrate to the true oscillator rate.
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci * Board-specific wiring options include using split power mode with
398c2ecf20Sopenharmony_ci * RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset),
408c2ecf20Sopenharmony_ci * and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from
418c2ecf20Sopenharmony_ci * low power modes) for OMAP1 boards (OMAP-L138 has this built into
428c2ecf20Sopenharmony_ci * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment.
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* RTC registers */
468c2ecf20Sopenharmony_ci#define OMAP_RTC_SECONDS_REG		0x00
478c2ecf20Sopenharmony_ci#define OMAP_RTC_MINUTES_REG		0x04
488c2ecf20Sopenharmony_ci#define OMAP_RTC_HOURS_REG		0x08
498c2ecf20Sopenharmony_ci#define OMAP_RTC_DAYS_REG		0x0C
508c2ecf20Sopenharmony_ci#define OMAP_RTC_MONTHS_REG		0x10
518c2ecf20Sopenharmony_ci#define OMAP_RTC_YEARS_REG		0x14
528c2ecf20Sopenharmony_ci#define OMAP_RTC_WEEKS_REG		0x18
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM_SECONDS_REG	0x20
558c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM_MINUTES_REG	0x24
568c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM_HOURS_REG	0x28
578c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM_DAYS_REG		0x2c
588c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM_MONTHS_REG	0x30
598c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM_YEARS_REG	0x34
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define OMAP_RTC_CTRL_REG		0x40
628c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_REG		0x44
638c2ecf20Sopenharmony_ci#define OMAP_RTC_INTERRUPTS_REG		0x48
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define OMAP_RTC_COMP_LSB_REG		0x4c
668c2ecf20Sopenharmony_ci#define OMAP_RTC_COMP_MSB_REG		0x50
678c2ecf20Sopenharmony_ci#define OMAP_RTC_OSC_REG		0x54
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define OMAP_RTC_SCRATCH0_REG		0x60
708c2ecf20Sopenharmony_ci#define OMAP_RTC_SCRATCH1_REG		0x64
718c2ecf20Sopenharmony_ci#define OMAP_RTC_SCRATCH2_REG		0x68
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define OMAP_RTC_KICK0_REG		0x6c
748c2ecf20Sopenharmony_ci#define OMAP_RTC_KICK1_REG		0x70
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define OMAP_RTC_IRQWAKEEN		0x7c
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM2_SECONDS_REG	0x80
798c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM2_MINUTES_REG	0x84
808c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM2_HOURS_REG	0x88
818c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM2_DAYS_REG	0x8c
828c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM2_MONTHS_REG	0x90
838c2ecf20Sopenharmony_ci#define OMAP_RTC_ALARM2_YEARS_REG	0x94
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define OMAP_RTC_PMIC_REG		0x98
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/* OMAP_RTC_CTRL_REG bit fields: */
888c2ecf20Sopenharmony_ci#define OMAP_RTC_CTRL_SPLIT		BIT(7)
898c2ecf20Sopenharmony_ci#define OMAP_RTC_CTRL_DISABLE		BIT(6)
908c2ecf20Sopenharmony_ci#define OMAP_RTC_CTRL_SET_32_COUNTER	BIT(5)
918c2ecf20Sopenharmony_ci#define OMAP_RTC_CTRL_TEST		BIT(4)
928c2ecf20Sopenharmony_ci#define OMAP_RTC_CTRL_MODE_12_24	BIT(3)
938c2ecf20Sopenharmony_ci#define OMAP_RTC_CTRL_AUTO_COMP		BIT(2)
948c2ecf20Sopenharmony_ci#define OMAP_RTC_CTRL_ROUND_30S		BIT(1)
958c2ecf20Sopenharmony_ci#define OMAP_RTC_CTRL_STOP		BIT(0)
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* OMAP_RTC_STATUS_REG bit fields: */
988c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_POWER_UP	BIT(7)
998c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_ALARM2		BIT(7)
1008c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_ALARM		BIT(6)
1018c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_1D_EVENT	BIT(5)
1028c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_1H_EVENT	BIT(4)
1038c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_1M_EVENT	BIT(3)
1048c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_1S_EVENT	BIT(2)
1058c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_RUN		BIT(1)
1068c2ecf20Sopenharmony_ci#define OMAP_RTC_STATUS_BUSY		BIT(0)
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/* OMAP_RTC_INTERRUPTS_REG bit fields: */
1098c2ecf20Sopenharmony_ci#define OMAP_RTC_INTERRUPTS_IT_ALARM2	BIT(4)
1108c2ecf20Sopenharmony_ci#define OMAP_RTC_INTERRUPTS_IT_ALARM	BIT(3)
1118c2ecf20Sopenharmony_ci#define OMAP_RTC_INTERRUPTS_IT_TIMER	BIT(2)
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/* OMAP_RTC_OSC_REG bit fields: */
1148c2ecf20Sopenharmony_ci#define OMAP_RTC_OSC_32KCLK_EN		BIT(6)
1158c2ecf20Sopenharmony_ci#define OMAP_RTC_OSC_SEL_32KCLK_SRC	BIT(3)
1168c2ecf20Sopenharmony_ci#define OMAP_RTC_OSC_OSC32K_GZ_DISABLE	BIT(4)
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/* OMAP_RTC_IRQWAKEEN bit fields: */
1198c2ecf20Sopenharmony_ci#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN	BIT(1)
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/* OMAP_RTC_PMIC bit fields: */
1228c2ecf20Sopenharmony_ci#define OMAP_RTC_PMIC_POWER_EN_EN	BIT(16)
1238c2ecf20Sopenharmony_ci#define OMAP_RTC_PMIC_EXT_WKUP_EN(x)	BIT(x)
1248c2ecf20Sopenharmony_ci#define OMAP_RTC_PMIC_EXT_WKUP_POL(x)	BIT(4 + x)
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/* OMAP_RTC_KICKER values */
1278c2ecf20Sopenharmony_ci#define	KICK0_VALUE			0x83e70b13
1288c2ecf20Sopenharmony_ci#define	KICK1_VALUE			0x95a4f1e0
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistruct omap_rtc;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistruct omap_rtc_device_type {
1338c2ecf20Sopenharmony_ci	bool has_32kclk_en;
1348c2ecf20Sopenharmony_ci	bool has_irqwakeen;
1358c2ecf20Sopenharmony_ci	bool has_pmic_mode;
1368c2ecf20Sopenharmony_ci	bool has_power_up_reset;
1378c2ecf20Sopenharmony_ci	void (*lock)(struct omap_rtc *rtc);
1388c2ecf20Sopenharmony_ci	void (*unlock)(struct omap_rtc *rtc);
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistruct omap_rtc {
1428c2ecf20Sopenharmony_ci	struct rtc_device *rtc;
1438c2ecf20Sopenharmony_ci	void __iomem *base;
1448c2ecf20Sopenharmony_ci	struct clk *clk;
1458c2ecf20Sopenharmony_ci	int irq_alarm;
1468c2ecf20Sopenharmony_ci	int irq_timer;
1478c2ecf20Sopenharmony_ci	u8 interrupts_reg;
1488c2ecf20Sopenharmony_ci	bool is_pmic_controller;
1498c2ecf20Sopenharmony_ci	bool has_ext_clk;
1508c2ecf20Sopenharmony_ci	bool is_suspending;
1518c2ecf20Sopenharmony_ci	const struct omap_rtc_device_type *type;
1528c2ecf20Sopenharmony_ci	struct pinctrl_dev *pctldev;
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	return readb(rtc->base + reg);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic inline u32 rtc_readl(struct omap_rtc *rtc, unsigned int reg)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	return readl(rtc->base + reg);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic inline void rtc_write(struct omap_rtc *rtc, unsigned int reg, u8 val)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	writeb(val, rtc->base + reg);
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic inline void rtc_writel(struct omap_rtc *rtc, unsigned int reg, u32 val)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	writel(val, rtc->base + reg);
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void am3352_rtc_unlock(struct omap_rtc *rtc)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE);
1788c2ecf20Sopenharmony_ci	rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic void am3352_rtc_lock(struct omap_rtc *rtc)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0);
1848c2ecf20Sopenharmony_ci	rtc_writel(rtc, OMAP_RTC_KICK1_REG, 0);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic void default_rtc_unlock(struct omap_rtc *rtc)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void default_rtc_lock(struct omap_rtc *rtc)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/*
1968c2ecf20Sopenharmony_ci * We rely on the rtc framework to handle locking (rtc->ops_lock),
1978c2ecf20Sopenharmony_ci * so the only other requirement is that register accesses which
1988c2ecf20Sopenharmony_ci * require BUSY to be clear are made with IRQs locally disabled
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_cistatic void rtc_wait_not_busy(struct omap_rtc *rtc)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	int count;
2038c2ecf20Sopenharmony_ci	u8 status;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/* BUSY may stay active for 1/32768 second (~30 usec) */
2068c2ecf20Sopenharmony_ci	for (count = 0; count < 50; count++) {
2078c2ecf20Sopenharmony_ci		status = rtc_read(rtc, OMAP_RTC_STATUS_REG);
2088c2ecf20Sopenharmony_ci		if (!(status & OMAP_RTC_STATUS_BUSY))
2098c2ecf20Sopenharmony_ci			break;
2108c2ecf20Sopenharmony_ci		udelay(1);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci	/* now we have ~15 usec to read/write various registers */
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic irqreturn_t rtc_irq(int irq, void *dev_id)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct omap_rtc	*rtc = dev_id;
2188c2ecf20Sopenharmony_ci	unsigned long events = 0;
2198c2ecf20Sopenharmony_ci	u8 irq_data;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	irq_data = rtc_read(rtc, OMAP_RTC_STATUS_REG);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	/* alarm irq? */
2248c2ecf20Sopenharmony_ci	if (irq_data & OMAP_RTC_STATUS_ALARM) {
2258c2ecf20Sopenharmony_ci		rtc->type->unlock(rtc);
2268c2ecf20Sopenharmony_ci		rtc_write(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM);
2278c2ecf20Sopenharmony_ci		rtc->type->lock(rtc);
2288c2ecf20Sopenharmony_ci		events |= RTC_IRQF | RTC_AF;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* 1/sec periodic/update irq? */
2328c2ecf20Sopenharmony_ci	if (irq_data & OMAP_RTC_STATUS_1S_EVENT)
2338c2ecf20Sopenharmony_ci		events |= RTC_IRQF | RTC_UF;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	rtc_update_irq(rtc->rtc, 1, events);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = dev_get_drvdata(dev);
2438c2ecf20Sopenharmony_ci	u8 reg, irqwake_reg = 0;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	local_irq_disable();
2468c2ecf20Sopenharmony_ci	rtc_wait_not_busy(rtc);
2478c2ecf20Sopenharmony_ci	reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
2488c2ecf20Sopenharmony_ci	if (rtc->type->has_irqwakeen)
2498c2ecf20Sopenharmony_ci		irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (enabled) {
2528c2ecf20Sopenharmony_ci		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
2538c2ecf20Sopenharmony_ci		irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
2548c2ecf20Sopenharmony_ci	} else {
2558c2ecf20Sopenharmony_ci		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
2568c2ecf20Sopenharmony_ci		irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci	rtc_wait_not_busy(rtc);
2598c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
2608c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);
2618c2ecf20Sopenharmony_ci	if (rtc->type->has_irqwakeen)
2628c2ecf20Sopenharmony_ci		rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);
2638c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
2648c2ecf20Sopenharmony_ci	local_irq_enable();
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	return 0;
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/* this hardware doesn't support "don't care" alarm fields */
2708c2ecf20Sopenharmony_cistatic void tm2bcd(struct rtc_time *tm)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	tm->tm_sec = bin2bcd(tm->tm_sec);
2738c2ecf20Sopenharmony_ci	tm->tm_min = bin2bcd(tm->tm_min);
2748c2ecf20Sopenharmony_ci	tm->tm_hour = bin2bcd(tm->tm_hour);
2758c2ecf20Sopenharmony_ci	tm->tm_mday = bin2bcd(tm->tm_mday);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	tm->tm_mon = bin2bcd(tm->tm_mon + 1);
2788c2ecf20Sopenharmony_ci	tm->tm_year = bin2bcd(tm->tm_year - 100);
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic void bcd2tm(struct rtc_time *tm)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	tm->tm_sec = bcd2bin(tm->tm_sec);
2848c2ecf20Sopenharmony_ci	tm->tm_min = bcd2bin(tm->tm_min);
2858c2ecf20Sopenharmony_ci	tm->tm_hour = bcd2bin(tm->tm_hour);
2868c2ecf20Sopenharmony_ci	tm->tm_mday = bcd2bin(tm->tm_mday);
2878c2ecf20Sopenharmony_ci	tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
2888c2ecf20Sopenharmony_ci	/* epoch == 1900 */
2898c2ecf20Sopenharmony_ci	tm->tm_year = bcd2bin(tm->tm_year) + 100;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic void omap_rtc_read_time_raw(struct omap_rtc *rtc, struct rtc_time *tm)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	tm->tm_sec = rtc_read(rtc, OMAP_RTC_SECONDS_REG);
2958c2ecf20Sopenharmony_ci	tm->tm_min = rtc_read(rtc, OMAP_RTC_MINUTES_REG);
2968c2ecf20Sopenharmony_ci	tm->tm_hour = rtc_read(rtc, OMAP_RTC_HOURS_REG);
2978c2ecf20Sopenharmony_ci	tm->tm_mday = rtc_read(rtc, OMAP_RTC_DAYS_REG);
2988c2ecf20Sopenharmony_ci	tm->tm_mon = rtc_read(rtc, OMAP_RTC_MONTHS_REG);
2998c2ecf20Sopenharmony_ci	tm->tm_year = rtc_read(rtc, OMAP_RTC_YEARS_REG);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int omap_rtc_read_time(struct device *dev, struct rtc_time *tm)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = dev_get_drvdata(dev);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* we don't report wday/yday/isdst ... */
3078c2ecf20Sopenharmony_ci	local_irq_disable();
3088c2ecf20Sopenharmony_ci	rtc_wait_not_busy(rtc);
3098c2ecf20Sopenharmony_ci	omap_rtc_read_time_raw(rtc, tm);
3108c2ecf20Sopenharmony_ci	local_irq_enable();
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	bcd2tm(tm);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return 0;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = dev_get_drvdata(dev);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	tm2bcd(tm);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	local_irq_disable();
3248c2ecf20Sopenharmony_ci	rtc_wait_not_busy(rtc);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
3278c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_YEARS_REG, tm->tm_year);
3288c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_MONTHS_REG, tm->tm_mon);
3298c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_DAYS_REG, tm->tm_mday);
3308c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_HOURS_REG, tm->tm_hour);
3318c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_MINUTES_REG, tm->tm_min);
3328c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_SECONDS_REG, tm->tm_sec);
3338c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	local_irq_enable();
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	return 0;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = dev_get_drvdata(dev);
3438c2ecf20Sopenharmony_ci	u8 interrupts;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	local_irq_disable();
3468c2ecf20Sopenharmony_ci	rtc_wait_not_busy(rtc);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	alm->time.tm_sec = rtc_read(rtc, OMAP_RTC_ALARM_SECONDS_REG);
3498c2ecf20Sopenharmony_ci	alm->time.tm_min = rtc_read(rtc, OMAP_RTC_ALARM_MINUTES_REG);
3508c2ecf20Sopenharmony_ci	alm->time.tm_hour = rtc_read(rtc, OMAP_RTC_ALARM_HOURS_REG);
3518c2ecf20Sopenharmony_ci	alm->time.tm_mday = rtc_read(rtc, OMAP_RTC_ALARM_DAYS_REG);
3528c2ecf20Sopenharmony_ci	alm->time.tm_mon = rtc_read(rtc, OMAP_RTC_ALARM_MONTHS_REG);
3538c2ecf20Sopenharmony_ci	alm->time.tm_year = rtc_read(rtc, OMAP_RTC_ALARM_YEARS_REG);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	local_irq_enable();
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	bcd2tm(&alm->time);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	interrupts = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
3608c2ecf20Sopenharmony_ci	alm->enabled = !!(interrupts & OMAP_RTC_INTERRUPTS_IT_ALARM);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return 0;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = dev_get_drvdata(dev);
3688c2ecf20Sopenharmony_ci	u8 reg, irqwake_reg = 0;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	tm2bcd(&alm->time);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	local_irq_disable();
3738c2ecf20Sopenharmony_ci	rtc_wait_not_busy(rtc);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
3768c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM_YEARS_REG, alm->time.tm_year);
3778c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM_MONTHS_REG, alm->time.tm_mon);
3788c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM_DAYS_REG, alm->time.tm_mday);
3798c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM_HOURS_REG, alm->time.tm_hour);
3808c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM_MINUTES_REG, alm->time.tm_min);
3818c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM_SECONDS_REG, alm->time.tm_sec);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
3848c2ecf20Sopenharmony_ci	if (rtc->type->has_irqwakeen)
3858c2ecf20Sopenharmony_ci		irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if (alm->enabled) {
3888c2ecf20Sopenharmony_ci		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
3898c2ecf20Sopenharmony_ci		irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
3908c2ecf20Sopenharmony_ci	} else {
3918c2ecf20Sopenharmony_ci		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
3928c2ecf20Sopenharmony_ci		irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);
3958c2ecf20Sopenharmony_ci	if (rtc->type->has_irqwakeen)
3968c2ecf20Sopenharmony_ci		rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);
3978c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	local_irq_enable();
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	return 0;
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic struct omap_rtc *omap_rtc_power_off_rtc;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/**
4078c2ecf20Sopenharmony_ci * omap_rtc_power_off_program: Set the pmic power off sequence. The RTC
4088c2ecf20Sopenharmony_ci * generates pmic_pwr_enable control, which can be used to control an external
4098c2ecf20Sopenharmony_ci * PMIC.
4108c2ecf20Sopenharmony_ci */
4118c2ecf20Sopenharmony_ciint omap_rtc_power_off_program(struct device *dev)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = omap_rtc_power_off_rtc;
4148c2ecf20Sopenharmony_ci	struct rtc_time tm;
4158c2ecf20Sopenharmony_ci	unsigned long now;
4168c2ecf20Sopenharmony_ci	int seconds;
4178c2ecf20Sopenharmony_ci	u32 val;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
4208c2ecf20Sopenharmony_ci	/* enable pmic_power_en control */
4218c2ecf20Sopenharmony_ci	val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
4228c2ecf20Sopenharmony_ci	rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ciagain:
4258c2ecf20Sopenharmony_ci	/* Clear any existing ALARM2 event */
4268c2ecf20Sopenharmony_ci	rtc_writel(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM2);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* set alarm one second from now */
4298c2ecf20Sopenharmony_ci	omap_rtc_read_time_raw(rtc, &tm);
4308c2ecf20Sopenharmony_ci	seconds = tm.tm_sec;
4318c2ecf20Sopenharmony_ci	bcd2tm(&tm);
4328c2ecf20Sopenharmony_ci	now = rtc_tm_to_time64(&tm);
4338c2ecf20Sopenharmony_ci	rtc_time64_to_tm(now + 1, &tm);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	tm2bcd(&tm);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	rtc_wait_not_busy(rtc);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM2_SECONDS_REG, tm.tm_sec);
4408c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM2_MINUTES_REG, tm.tm_min);
4418c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM2_HOURS_REG, tm.tm_hour);
4428c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM2_DAYS_REG, tm.tm_mday);
4438c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM2_MONTHS_REG, tm.tm_mon);
4448c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_ALARM2_YEARS_REG, tm.tm_year);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/*
4478c2ecf20Sopenharmony_ci	 * enable ALARM2 interrupt
4488c2ecf20Sopenharmony_ci	 *
4498c2ecf20Sopenharmony_ci	 * NOTE: this fails on AM3352 if rtc_write (writeb) is used
4508c2ecf20Sopenharmony_ci	 */
4518c2ecf20Sopenharmony_ci	val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
4528c2ecf20Sopenharmony_ci	rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG,
4538c2ecf20Sopenharmony_ci			val | OMAP_RTC_INTERRUPTS_IT_ALARM2);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/* Retry in case roll over happened before alarm was armed. */
4568c2ecf20Sopenharmony_ci	if (rtc_read(rtc, OMAP_RTC_SECONDS_REG) != seconds) {
4578c2ecf20Sopenharmony_ci		val = rtc_read(rtc, OMAP_RTC_STATUS_REG);
4588c2ecf20Sopenharmony_ci		if (!(val & OMAP_RTC_STATUS_ALARM2))
4598c2ecf20Sopenharmony_ci			goto again;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	return 0;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_rtc_power_off_program);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci/*
4698c2ecf20Sopenharmony_ci * omap_rtc_poweroff: RTC-controlled power off
4708c2ecf20Sopenharmony_ci *
4718c2ecf20Sopenharmony_ci * The RTC can be used to control an external PMIC via the pmic_power_en pin,
4728c2ecf20Sopenharmony_ci * which can be configured to transition to OFF on ALARM2 events.
4738c2ecf20Sopenharmony_ci *
4748c2ecf20Sopenharmony_ci * Notes:
4758c2ecf20Sopenharmony_ci * The one-second alarm offset is the shortest offset possible as the alarm
4768c2ecf20Sopenharmony_ci * registers must be set before the next timer update and the offset
4778c2ecf20Sopenharmony_ci * calculation is too heavy for everything to be done within a single access
4788c2ecf20Sopenharmony_ci * period (~15 us).
4798c2ecf20Sopenharmony_ci *
4808c2ecf20Sopenharmony_ci * Called with local interrupts disabled.
4818c2ecf20Sopenharmony_ci */
4828c2ecf20Sopenharmony_cistatic void omap_rtc_power_off(void)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc;
4858c2ecf20Sopenharmony_ci	u32 val;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	omap_rtc_power_off_program(rtc->dev.parent);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */
4908c2ecf20Sopenharmony_ci	omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc);
4918c2ecf20Sopenharmony_ci	val = rtc_readl(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG);
4928c2ecf20Sopenharmony_ci	val |= OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL(0) |
4938c2ecf20Sopenharmony_ci			OMAP_RTC_PMIC_EXT_WKUP_EN(0);
4948c2ecf20Sopenharmony_ci	rtc_writel(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG, val);
4958c2ecf20Sopenharmony_ci	omap_rtc_power_off_rtc->type->lock(omap_rtc_power_off_rtc);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	/*
4988c2ecf20Sopenharmony_ci	 * Wait for alarm to trigger (within one second) and external PMIC to
4998c2ecf20Sopenharmony_ci	 * power off the system. Add a 500 ms margin for external latencies
5008c2ecf20Sopenharmony_ci	 * (e.g. debounce circuits).
5018c2ecf20Sopenharmony_ci	 */
5028c2ecf20Sopenharmony_ci	mdelay(1500);
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_cistatic const struct rtc_class_ops omap_rtc_ops = {
5068c2ecf20Sopenharmony_ci	.read_time	= omap_rtc_read_time,
5078c2ecf20Sopenharmony_ci	.set_time	= omap_rtc_set_time,
5088c2ecf20Sopenharmony_ci	.read_alarm	= omap_rtc_read_alarm,
5098c2ecf20Sopenharmony_ci	.set_alarm	= omap_rtc_set_alarm,
5108c2ecf20Sopenharmony_ci	.alarm_irq_enable = omap_rtc_alarm_irq_enable,
5118c2ecf20Sopenharmony_ci};
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic const struct omap_rtc_device_type omap_rtc_default_type = {
5148c2ecf20Sopenharmony_ci	.has_power_up_reset = true,
5158c2ecf20Sopenharmony_ci	.lock		= default_rtc_lock,
5168c2ecf20Sopenharmony_ci	.unlock		= default_rtc_unlock,
5178c2ecf20Sopenharmony_ci};
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic const struct omap_rtc_device_type omap_rtc_am3352_type = {
5208c2ecf20Sopenharmony_ci	.has_32kclk_en	= true,
5218c2ecf20Sopenharmony_ci	.has_irqwakeen	= true,
5228c2ecf20Sopenharmony_ci	.has_pmic_mode	= true,
5238c2ecf20Sopenharmony_ci	.lock		= am3352_rtc_lock,
5248c2ecf20Sopenharmony_ci	.unlock		= am3352_rtc_unlock,
5258c2ecf20Sopenharmony_ci};
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic const struct omap_rtc_device_type omap_rtc_da830_type = {
5288c2ecf20Sopenharmony_ci	.lock		= am3352_rtc_lock,
5298c2ecf20Sopenharmony_ci	.unlock		= am3352_rtc_unlock,
5308c2ecf20Sopenharmony_ci};
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic const struct platform_device_id omap_rtc_id_table[] = {
5338c2ecf20Sopenharmony_ci	{
5348c2ecf20Sopenharmony_ci		.name	= "omap_rtc",
5358c2ecf20Sopenharmony_ci		.driver_data = (kernel_ulong_t)&omap_rtc_default_type,
5368c2ecf20Sopenharmony_ci	}, {
5378c2ecf20Sopenharmony_ci		.name	= "am3352-rtc",
5388c2ecf20Sopenharmony_ci		.driver_data = (kernel_ulong_t)&omap_rtc_am3352_type,
5398c2ecf20Sopenharmony_ci	}, {
5408c2ecf20Sopenharmony_ci		.name	= "da830-rtc",
5418c2ecf20Sopenharmony_ci		.driver_data = (kernel_ulong_t)&omap_rtc_da830_type,
5428c2ecf20Sopenharmony_ci	}, {
5438c2ecf20Sopenharmony_ci		/* sentinel */
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci};
5468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, omap_rtc_id_table);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic const struct of_device_id omap_rtc_of_match[] = {
5498c2ecf20Sopenharmony_ci	{
5508c2ecf20Sopenharmony_ci		.compatible	= "ti,am3352-rtc",
5518c2ecf20Sopenharmony_ci		.data		= &omap_rtc_am3352_type,
5528c2ecf20Sopenharmony_ci	}, {
5538c2ecf20Sopenharmony_ci		.compatible	= "ti,da830-rtc",
5548c2ecf20Sopenharmony_ci		.data		= &omap_rtc_da830_type,
5558c2ecf20Sopenharmony_ci	}, {
5568c2ecf20Sopenharmony_ci		/* sentinel */
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci};
5598c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_rtc_of_match);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic const struct pinctrl_pin_desc rtc_pins_desc[] = {
5628c2ecf20Sopenharmony_ci	PINCTRL_PIN(0, "ext_wakeup0"),
5638c2ecf20Sopenharmony_ci	PINCTRL_PIN(1, "ext_wakeup1"),
5648c2ecf20Sopenharmony_ci	PINCTRL_PIN(2, "ext_wakeup2"),
5658c2ecf20Sopenharmony_ci	PINCTRL_PIN(3, "ext_wakeup3"),
5668c2ecf20Sopenharmony_ci};
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic int rtc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	return 0;
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic const char *rtc_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
5748c2ecf20Sopenharmony_ci					unsigned int group)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	return NULL;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic const struct pinctrl_ops rtc_pinctrl_ops = {
5808c2ecf20Sopenharmony_ci	.get_groups_count = rtc_pinctrl_get_groups_count,
5818c2ecf20Sopenharmony_ci	.get_group_name = rtc_pinctrl_get_group_name,
5828c2ecf20Sopenharmony_ci	.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
5838c2ecf20Sopenharmony_ci	.dt_free_map = pinconf_generic_dt_free_map,
5848c2ecf20Sopenharmony_ci};
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci#define PIN_CONFIG_ACTIVE_HIGH		(PIN_CONFIG_END + 1)
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic const struct pinconf_generic_params rtc_params[] = {
5898c2ecf20Sopenharmony_ci	{"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0},
5908c2ecf20Sopenharmony_ci};
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
5938c2ecf20Sopenharmony_cistatic const struct pin_config_item rtc_conf_items[ARRAY_SIZE(rtc_params)] = {
5948c2ecf20Sopenharmony_ci	PCONFDUMP(PIN_CONFIG_ACTIVE_HIGH, "input active high", NULL, false),
5958c2ecf20Sopenharmony_ci};
5968c2ecf20Sopenharmony_ci#endif
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_cistatic int rtc_pinconf_get(struct pinctrl_dev *pctldev,
5998c2ecf20Sopenharmony_ci			unsigned int pin, unsigned long *config)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
6028c2ecf20Sopenharmony_ci	unsigned int param = pinconf_to_config_param(*config);
6038c2ecf20Sopenharmony_ci	u32 val;
6048c2ecf20Sopenharmony_ci	u16 arg = 0;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	switch (param) {
6098c2ecf20Sopenharmony_ci	case PIN_CONFIG_INPUT_ENABLE:
6108c2ecf20Sopenharmony_ci		if (!(val & OMAP_RTC_PMIC_EXT_WKUP_EN(pin)))
6118c2ecf20Sopenharmony_ci			return -EINVAL;
6128c2ecf20Sopenharmony_ci		break;
6138c2ecf20Sopenharmony_ci	case PIN_CONFIG_ACTIVE_HIGH:
6148c2ecf20Sopenharmony_ci		if (val & OMAP_RTC_PMIC_EXT_WKUP_POL(pin))
6158c2ecf20Sopenharmony_ci			return -EINVAL;
6168c2ecf20Sopenharmony_ci		break;
6178c2ecf20Sopenharmony_ci	default:
6188c2ecf20Sopenharmony_ci		return -ENOTSUPP;
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	*config = pinconf_to_config_packed(param, arg);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	return 0;
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistatic int rtc_pinconf_set(struct pinctrl_dev *pctldev,
6278c2ecf20Sopenharmony_ci			unsigned int pin, unsigned long *configs,
6288c2ecf20Sopenharmony_ci			unsigned int num_configs)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
6318c2ecf20Sopenharmony_ci	u32 val;
6328c2ecf20Sopenharmony_ci	unsigned int param;
6338c2ecf20Sopenharmony_ci	u32 param_val;
6348c2ecf20Sopenharmony_ci	int i;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/* active low by default */
6398c2ecf20Sopenharmony_ci	val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	for (i = 0; i < num_configs; i++) {
6428c2ecf20Sopenharmony_ci		param = pinconf_to_config_param(configs[i]);
6438c2ecf20Sopenharmony_ci		param_val = pinconf_to_config_argument(configs[i]);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		switch (param) {
6468c2ecf20Sopenharmony_ci		case PIN_CONFIG_INPUT_ENABLE:
6478c2ecf20Sopenharmony_ci			if (param_val)
6488c2ecf20Sopenharmony_ci				val |= OMAP_RTC_PMIC_EXT_WKUP_EN(pin);
6498c2ecf20Sopenharmony_ci			else
6508c2ecf20Sopenharmony_ci				val &= ~OMAP_RTC_PMIC_EXT_WKUP_EN(pin);
6518c2ecf20Sopenharmony_ci			break;
6528c2ecf20Sopenharmony_ci		case PIN_CONFIG_ACTIVE_HIGH:
6538c2ecf20Sopenharmony_ci			val &= ~OMAP_RTC_PMIC_EXT_WKUP_POL(pin);
6548c2ecf20Sopenharmony_ci			break;
6558c2ecf20Sopenharmony_ci		default:
6568c2ecf20Sopenharmony_ci			dev_err(&rtc->rtc->dev, "Property %u not supported\n",
6578c2ecf20Sopenharmony_ci				param);
6588c2ecf20Sopenharmony_ci			return -ENOTSUPP;
6598c2ecf20Sopenharmony_ci		}
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
6638c2ecf20Sopenharmony_ci	rtc_writel(rtc, OMAP_RTC_PMIC_REG, val);
6648c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	return 0;
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_cistatic const struct pinconf_ops rtc_pinconf_ops = {
6708c2ecf20Sopenharmony_ci	.is_generic = true,
6718c2ecf20Sopenharmony_ci	.pin_config_get = rtc_pinconf_get,
6728c2ecf20Sopenharmony_ci	.pin_config_set = rtc_pinconf_set,
6738c2ecf20Sopenharmony_ci};
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic struct pinctrl_desc rtc_pinctrl_desc = {
6768c2ecf20Sopenharmony_ci	.pins = rtc_pins_desc,
6778c2ecf20Sopenharmony_ci	.npins = ARRAY_SIZE(rtc_pins_desc),
6788c2ecf20Sopenharmony_ci	.pctlops = &rtc_pinctrl_ops,
6798c2ecf20Sopenharmony_ci	.confops = &rtc_pinconf_ops,
6808c2ecf20Sopenharmony_ci	.custom_params = rtc_params,
6818c2ecf20Sopenharmony_ci	.num_custom_params = ARRAY_SIZE(rtc_params),
6828c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
6838c2ecf20Sopenharmony_ci	.custom_conf_items = rtc_conf_items,
6848c2ecf20Sopenharmony_ci#endif
6858c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
6868c2ecf20Sopenharmony_ci};
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_cistatic int omap_rtc_scratch_read(void *priv, unsigned int offset, void *_val,
6898c2ecf20Sopenharmony_ci				 size_t bytes)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	struct omap_rtc	*rtc = priv;
6928c2ecf20Sopenharmony_ci	u32 *val = _val;
6938c2ecf20Sopenharmony_ci	int i;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	for (i = 0; i < bytes / 4; i++)
6968c2ecf20Sopenharmony_ci		val[i] = rtc_readl(rtc,
6978c2ecf20Sopenharmony_ci				   OMAP_RTC_SCRATCH0_REG + offset + (i * 4));
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	return 0;
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_cistatic int omap_rtc_scratch_write(void *priv, unsigned int offset, void *_val,
7038c2ecf20Sopenharmony_ci				  size_t bytes)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct omap_rtc	*rtc = priv;
7068c2ecf20Sopenharmony_ci	u32 *val = _val;
7078c2ecf20Sopenharmony_ci	int i;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
7108c2ecf20Sopenharmony_ci	for (i = 0; i < bytes / 4; i++)
7118c2ecf20Sopenharmony_ci		rtc_writel(rtc,
7128c2ecf20Sopenharmony_ci			   OMAP_RTC_SCRATCH0_REG + offset + (i * 4), val[i]);
7138c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	return 0;
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_cistatic struct nvmem_config omap_rtc_nvmem_config = {
7198c2ecf20Sopenharmony_ci	.name = "omap_rtc_scratch",
7208c2ecf20Sopenharmony_ci	.word_size = 4,
7218c2ecf20Sopenharmony_ci	.stride = 4,
7228c2ecf20Sopenharmony_ci	.size = OMAP_RTC_KICK0_REG - OMAP_RTC_SCRATCH0_REG,
7238c2ecf20Sopenharmony_ci	.reg_read = omap_rtc_scratch_read,
7248c2ecf20Sopenharmony_ci	.reg_write = omap_rtc_scratch_write,
7258c2ecf20Sopenharmony_ci};
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic int omap_rtc_probe(struct platform_device *pdev)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	struct omap_rtc	*rtc;
7308c2ecf20Sopenharmony_ci	u8 reg, mask, new_ctrl;
7318c2ecf20Sopenharmony_ci	const struct platform_device_id *id_entry;
7328c2ecf20Sopenharmony_ci	const struct of_device_id *of_id;
7338c2ecf20Sopenharmony_ci	int ret;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
7368c2ecf20Sopenharmony_ci	if (!rtc)
7378c2ecf20Sopenharmony_ci		return -ENOMEM;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	of_id = of_match_device(omap_rtc_of_match, &pdev->dev);
7408c2ecf20Sopenharmony_ci	if (of_id) {
7418c2ecf20Sopenharmony_ci		rtc->type = of_id->data;
7428c2ecf20Sopenharmony_ci		rtc->is_pmic_controller = rtc->type->has_pmic_mode &&
7438c2ecf20Sopenharmony_ci			of_device_is_system_power_controller(pdev->dev.of_node);
7448c2ecf20Sopenharmony_ci	} else {
7458c2ecf20Sopenharmony_ci		id_entry = platform_get_device_id(pdev);
7468c2ecf20Sopenharmony_ci		rtc->type = (void *)id_entry->driver_data;
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	rtc->irq_timer = platform_get_irq(pdev, 0);
7508c2ecf20Sopenharmony_ci	if (rtc->irq_timer <= 0)
7518c2ecf20Sopenharmony_ci		return -ENOENT;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	rtc->irq_alarm = platform_get_irq(pdev, 1);
7548c2ecf20Sopenharmony_ci	if (rtc->irq_alarm <= 0)
7558c2ecf20Sopenharmony_ci		return -ENOENT;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	rtc->clk = devm_clk_get(&pdev->dev, "ext-clk");
7588c2ecf20Sopenharmony_ci	if (!IS_ERR(rtc->clk))
7598c2ecf20Sopenharmony_ci		rtc->has_ext_clk = true;
7608c2ecf20Sopenharmony_ci	else
7618c2ecf20Sopenharmony_ci		rtc->clk = devm_clk_get(&pdev->dev, "int-clk");
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	if (!IS_ERR(rtc->clk))
7648c2ecf20Sopenharmony_ci		clk_prepare_enable(rtc->clk);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	rtc->base = devm_platform_ioremap_resource(pdev, 0);
7678c2ecf20Sopenharmony_ci	if (IS_ERR(rtc->base)) {
7688c2ecf20Sopenharmony_ci		clk_disable_unprepare(rtc->clk);
7698c2ecf20Sopenharmony_ci		return PTR_ERR(rtc->base);
7708c2ecf20Sopenharmony_ci	}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, rtc);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	/* Enable the clock/module so that we can access the registers */
7758c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
7768c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	/*
7818c2ecf20Sopenharmony_ci	 * disable interrupts
7828c2ecf20Sopenharmony_ci	 *
7838c2ecf20Sopenharmony_ci	 * NOTE: ALARM2 is not cleared on AM3352 if rtc_write (writeb) is used
7848c2ecf20Sopenharmony_ci	 */
7858c2ecf20Sopenharmony_ci	rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	/* enable RTC functional clock */
7888c2ecf20Sopenharmony_ci	if (rtc->type->has_32kclk_en) {
7898c2ecf20Sopenharmony_ci		reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
7908c2ecf20Sopenharmony_ci		rtc_writel(rtc, OMAP_RTC_OSC_REG,
7918c2ecf20Sopenharmony_ci				reg | OMAP_RTC_OSC_32KCLK_EN);
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	/* clear old status */
7958c2ecf20Sopenharmony_ci	reg = rtc_read(rtc, OMAP_RTC_STATUS_REG);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	mask = OMAP_RTC_STATUS_ALARM;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	if (rtc->type->has_pmic_mode)
8008c2ecf20Sopenharmony_ci		mask |= OMAP_RTC_STATUS_ALARM2;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	if (rtc->type->has_power_up_reset) {
8038c2ecf20Sopenharmony_ci		mask |= OMAP_RTC_STATUS_POWER_UP;
8048c2ecf20Sopenharmony_ci		if (reg & OMAP_RTC_STATUS_POWER_UP)
8058c2ecf20Sopenharmony_ci			dev_info(&pdev->dev, "RTC power up reset detected\n");
8068c2ecf20Sopenharmony_ci	}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	if (reg & mask)
8098c2ecf20Sopenharmony_ci		rtc_write(rtc, OMAP_RTC_STATUS_REG, reg & mask);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	/* On boards with split power, RTC_ON_NOFF won't reset the RTC */
8128c2ecf20Sopenharmony_ci	reg = rtc_read(rtc, OMAP_RTC_CTRL_REG);
8138c2ecf20Sopenharmony_ci	if (reg & OMAP_RTC_CTRL_STOP)
8148c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "already running\n");
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	/* force to 24 hour mode */
8178c2ecf20Sopenharmony_ci	new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT | OMAP_RTC_CTRL_AUTO_COMP);
8188c2ecf20Sopenharmony_ci	new_ctrl |= OMAP_RTC_CTRL_STOP;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	/*
8218c2ecf20Sopenharmony_ci	 * BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
8228c2ecf20Sopenharmony_ci	 *
8238c2ecf20Sopenharmony_ci	 *  - Device wake-up capability setting should come through chip
8248c2ecf20Sopenharmony_ci	 *    init logic. OMAP1 boards should initialize the "wakeup capable"
8258c2ecf20Sopenharmony_ci	 *    flag in the platform device if the board is wired right for
8268c2ecf20Sopenharmony_ci	 *    being woken up by RTC alarm. For OMAP-L138, this capability
8278c2ecf20Sopenharmony_ci	 *    is built into the SoC by the "Deep Sleep" capability.
8288c2ecf20Sopenharmony_ci	 *
8298c2ecf20Sopenharmony_ci	 *  - Boards wired so RTC_ON_nOFF is used as the reset signal,
8308c2ecf20Sopenharmony_ci	 *    rather than nPWRON_RESET, should forcibly enable split
8318c2ecf20Sopenharmony_ci	 *    power mode.  (Some chip errata report that RTC_CTRL_SPLIT
8328c2ecf20Sopenharmony_ci	 *    is write-only, and always reads as zero...)
8338c2ecf20Sopenharmony_ci	 */
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	if (new_ctrl & OMAP_RTC_CTRL_SPLIT)
8368c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "split power mode\n");
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	if (reg != new_ctrl)
8398c2ecf20Sopenharmony_ci		rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	/*
8428c2ecf20Sopenharmony_ci	 * If we have the external clock then switch to it so we can keep
8438c2ecf20Sopenharmony_ci	 * ticking across suspend.
8448c2ecf20Sopenharmony_ci	 */
8458c2ecf20Sopenharmony_ci	if (rtc->has_ext_clk) {
8468c2ecf20Sopenharmony_ci		reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
8478c2ecf20Sopenharmony_ci		reg &= ~OMAP_RTC_OSC_OSC32K_GZ_DISABLE;
8488c2ecf20Sopenharmony_ci		reg |= OMAP_RTC_OSC_32KCLK_EN | OMAP_RTC_OSC_SEL_32KCLK_SRC;
8498c2ecf20Sopenharmony_ci		rtc_writel(rtc, OMAP_RTC_OSC_REG, reg);
8508c2ecf20Sopenharmony_ci	}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	device_init_wakeup(&pdev->dev, true);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
8578c2ecf20Sopenharmony_ci	if (IS_ERR(rtc->rtc)) {
8588c2ecf20Sopenharmony_ci		ret = PTR_ERR(rtc->rtc);
8598c2ecf20Sopenharmony_ci		goto err;
8608c2ecf20Sopenharmony_ci	}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	rtc->rtc->ops = &omap_rtc_ops;
8638c2ecf20Sopenharmony_ci	rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
8648c2ecf20Sopenharmony_ci	rtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
8658c2ecf20Sopenharmony_ci	omap_rtc_nvmem_config.priv = rtc;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	/* handle periodic and alarm irqs */
8688c2ecf20Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, rtc->irq_timer, rtc_irq, 0,
8698c2ecf20Sopenharmony_ci			dev_name(&rtc->rtc->dev), rtc);
8708c2ecf20Sopenharmony_ci	if (ret)
8718c2ecf20Sopenharmony_ci		goto err;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	if (rtc->irq_timer != rtc->irq_alarm) {
8748c2ecf20Sopenharmony_ci		ret = devm_request_irq(&pdev->dev, rtc->irq_alarm, rtc_irq, 0,
8758c2ecf20Sopenharmony_ci				dev_name(&rtc->rtc->dev), rtc);
8768c2ecf20Sopenharmony_ci		if (ret)
8778c2ecf20Sopenharmony_ci			goto err;
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	/* Support ext_wakeup pinconf */
8818c2ecf20Sopenharmony_ci	rtc_pinctrl_desc.name = dev_name(&pdev->dev);
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	rtc->pctldev = pinctrl_register(&rtc_pinctrl_desc, &pdev->dev, rtc);
8848c2ecf20Sopenharmony_ci	if (IS_ERR(rtc->pctldev)) {
8858c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
8868c2ecf20Sopenharmony_ci		ret = PTR_ERR(rtc->pctldev);
8878c2ecf20Sopenharmony_ci		goto err;
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	ret = rtc_register_device(rtc->rtc);
8918c2ecf20Sopenharmony_ci	if (ret)
8928c2ecf20Sopenharmony_ci		goto err_deregister_pinctrl;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	rtc_nvmem_register(rtc->rtc, &omap_rtc_nvmem_config);
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	if (rtc->is_pmic_controller) {
8978c2ecf20Sopenharmony_ci		if (!pm_power_off) {
8988c2ecf20Sopenharmony_ci			omap_rtc_power_off_rtc = rtc;
8998c2ecf20Sopenharmony_ci			pm_power_off = omap_rtc_power_off;
9008c2ecf20Sopenharmony_ci		}
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	return 0;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_cierr_deregister_pinctrl:
9068c2ecf20Sopenharmony_ci	pinctrl_unregister(rtc->pctldev);
9078c2ecf20Sopenharmony_cierr:
9088c2ecf20Sopenharmony_ci	clk_disable_unprepare(rtc->clk);
9098c2ecf20Sopenharmony_ci	device_init_wakeup(&pdev->dev, false);
9108c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
9118c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
9128c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	return ret;
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cistatic int omap_rtc_remove(struct platform_device *pdev)
9188c2ecf20Sopenharmony_ci{
9198c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = platform_get_drvdata(pdev);
9208c2ecf20Sopenharmony_ci	u8 reg;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	if (pm_power_off == omap_rtc_power_off &&
9238c2ecf20Sopenharmony_ci			omap_rtc_power_off_rtc == rtc) {
9248c2ecf20Sopenharmony_ci		pm_power_off = NULL;
9258c2ecf20Sopenharmony_ci		omap_rtc_power_off_rtc = NULL;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	device_init_wakeup(&pdev->dev, 0);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	if (!IS_ERR(rtc->clk))
9318c2ecf20Sopenharmony_ci		clk_disable_unprepare(rtc->clk);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
9348c2ecf20Sopenharmony_ci	/* leave rtc running, but disable irqs */
9358c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	if (rtc->has_ext_clk) {
9388c2ecf20Sopenharmony_ci		reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
9398c2ecf20Sopenharmony_ci		reg &= ~OMAP_RTC_OSC_SEL_32KCLK_SRC;
9408c2ecf20Sopenharmony_ci		rtc_write(rtc, OMAP_RTC_OSC_REG, reg);
9418c2ecf20Sopenharmony_ci	}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	/* Disable the clock/module */
9468c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
9478c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	/* Remove ext_wakeup pinconf */
9508c2ecf20Sopenharmony_ci	pinctrl_unregister(rtc->pctldev);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	return 0;
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic int __maybe_unused omap_rtc_suspend(struct device *dev)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = dev_get_drvdata(dev);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	rtc->interrupts_reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
9628c2ecf20Sopenharmony_ci	/*
9638c2ecf20Sopenharmony_ci	 * FIXME: the RTC alarm is not currently acting as a wakeup event
9648c2ecf20Sopenharmony_ci	 * source on some platforms, and in fact this enable() call is just
9658c2ecf20Sopenharmony_ci	 * saving a flag that's never used...
9668c2ecf20Sopenharmony_ci	 */
9678c2ecf20Sopenharmony_ci	if (device_may_wakeup(dev))
9688c2ecf20Sopenharmony_ci		enable_irq_wake(rtc->irq_alarm);
9698c2ecf20Sopenharmony_ci	else
9708c2ecf20Sopenharmony_ci		rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
9718c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	rtc->is_suspending = true;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	return 0;
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_cistatic int __maybe_unused omap_rtc_resume(struct device *dev)
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = dev_get_drvdata(dev);
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
9838c2ecf20Sopenharmony_ci	if (device_may_wakeup(dev))
9848c2ecf20Sopenharmony_ci		disable_irq_wake(rtc->irq_alarm);
9858c2ecf20Sopenharmony_ci	else
9868c2ecf20Sopenharmony_ci		rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, rtc->interrupts_reg);
9878c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	rtc->is_suspending = false;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	return 0;
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_cistatic int __maybe_unused omap_rtc_runtime_suspend(struct device *dev)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = dev_get_drvdata(dev);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	if (rtc->is_suspending && !rtc->has_ext_clk)
9998c2ecf20Sopenharmony_ci		return -EBUSY;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	return 0;
10028c2ecf20Sopenharmony_ci}
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_cistatic const struct dev_pm_ops omap_rtc_pm_ops = {
10058c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(omap_rtc_suspend, omap_rtc_resume)
10068c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(omap_rtc_runtime_suspend, NULL, NULL)
10078c2ecf20Sopenharmony_ci};
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_cistatic void omap_rtc_shutdown(struct platform_device *pdev)
10108c2ecf20Sopenharmony_ci{
10118c2ecf20Sopenharmony_ci	struct omap_rtc *rtc = platform_get_drvdata(pdev);
10128c2ecf20Sopenharmony_ci	u8 mask;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	/*
10158c2ecf20Sopenharmony_ci	 * Keep the ALARM interrupt enabled to allow the system to power up on
10168c2ecf20Sopenharmony_ci	 * alarm events.
10178c2ecf20Sopenharmony_ci	 */
10188c2ecf20Sopenharmony_ci	rtc->type->unlock(rtc);
10198c2ecf20Sopenharmony_ci	mask = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
10208c2ecf20Sopenharmony_ci	mask &= OMAP_RTC_INTERRUPTS_IT_ALARM;
10218c2ecf20Sopenharmony_ci	rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, mask);
10228c2ecf20Sopenharmony_ci	rtc->type->lock(rtc);
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_cistatic struct platform_driver omap_rtc_driver = {
10268c2ecf20Sopenharmony_ci	.probe		= omap_rtc_probe,
10278c2ecf20Sopenharmony_ci	.remove		= omap_rtc_remove,
10288c2ecf20Sopenharmony_ci	.shutdown	= omap_rtc_shutdown,
10298c2ecf20Sopenharmony_ci	.driver		= {
10308c2ecf20Sopenharmony_ci		.name	= "omap_rtc",
10318c2ecf20Sopenharmony_ci		.pm	= &omap_rtc_pm_ops,
10328c2ecf20Sopenharmony_ci		.of_match_table = omap_rtc_of_match,
10338c2ecf20Sopenharmony_ci	},
10348c2ecf20Sopenharmony_ci	.id_table	= omap_rtc_id_table,
10358c2ecf20Sopenharmony_ci};
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cimodule_platform_driver(omap_rtc_driver);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:omap_rtc");
10408c2ecf20Sopenharmony_ciMODULE_AUTHOR("George G. Davis (and others)");
10418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1042