18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * A RTC driver for the Simtek STK17TA8
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * By Thomas Hommel <thomas.hommel@ge.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Based on the DS1553 driver from
88c2ecf20Sopenharmony_ci * Atsushi Nemoto <anemo@mba.ocn.ne.jp>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/bcd.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/gfp.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
178c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
188c2ecf20Sopenharmony_ci#include <linux/rtc.h>
198c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
208c2ecf20Sopenharmony_ci#include <linux/io.h>
218c2ecf20Sopenharmony_ci#include <linux/module.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define RTC_REG_SIZE		0x20000
248c2ecf20Sopenharmony_ci#define RTC_OFFSET		0x1fff0
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define RTC_FLAGS		(RTC_OFFSET + 0)
278c2ecf20Sopenharmony_ci#define RTC_CENTURY		(RTC_OFFSET + 1)
288c2ecf20Sopenharmony_ci#define RTC_SECONDS_ALARM	(RTC_OFFSET + 2)
298c2ecf20Sopenharmony_ci#define RTC_MINUTES_ALARM	(RTC_OFFSET + 3)
308c2ecf20Sopenharmony_ci#define RTC_HOURS_ALARM		(RTC_OFFSET + 4)
318c2ecf20Sopenharmony_ci#define RTC_DATE_ALARM		(RTC_OFFSET + 5)
328c2ecf20Sopenharmony_ci#define RTC_INTERRUPTS		(RTC_OFFSET + 6)
338c2ecf20Sopenharmony_ci#define RTC_WATCHDOG		(RTC_OFFSET + 7)
348c2ecf20Sopenharmony_ci#define RTC_CALIBRATION		(RTC_OFFSET + 8)
358c2ecf20Sopenharmony_ci#define RTC_SECONDS		(RTC_OFFSET + 9)
368c2ecf20Sopenharmony_ci#define RTC_MINUTES		(RTC_OFFSET + 10)
378c2ecf20Sopenharmony_ci#define RTC_HOURS		(RTC_OFFSET + 11)
388c2ecf20Sopenharmony_ci#define RTC_DAY			(RTC_OFFSET + 12)
398c2ecf20Sopenharmony_ci#define RTC_DATE		(RTC_OFFSET + 13)
408c2ecf20Sopenharmony_ci#define RTC_MONTH		(RTC_OFFSET + 14)
418c2ecf20Sopenharmony_ci#define RTC_YEAR		(RTC_OFFSET + 15)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define RTC_SECONDS_MASK	0x7f
448c2ecf20Sopenharmony_ci#define RTC_DAY_MASK		0x07
458c2ecf20Sopenharmony_ci#define RTC_CAL_MASK		0x3f
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/* Bits in the Calibration register */
488c2ecf20Sopenharmony_ci#define RTC_STOP		0x80
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* Bits in the Flags register */
518c2ecf20Sopenharmony_ci#define RTC_FLAGS_AF		0x40
528c2ecf20Sopenharmony_ci#define RTC_FLAGS_PF		0x20
538c2ecf20Sopenharmony_ci#define RTC_WRITE		0x02
548c2ecf20Sopenharmony_ci#define RTC_READ		0x01
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/* Bits in the Interrupts register */
578c2ecf20Sopenharmony_ci#define RTC_INTS_AIE		0x40
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistruct rtc_plat_data {
608c2ecf20Sopenharmony_ci	struct rtc_device *rtc;
618c2ecf20Sopenharmony_ci	void __iomem *ioaddr;
628c2ecf20Sopenharmony_ci	unsigned long last_jiffies;
638c2ecf20Sopenharmony_ci	int irq;
648c2ecf20Sopenharmony_ci	unsigned int irqen;
658c2ecf20Sopenharmony_ci	int alrm_sec;
668c2ecf20Sopenharmony_ci	int alrm_min;
678c2ecf20Sopenharmony_ci	int alrm_hour;
688c2ecf20Sopenharmony_ci	int alrm_mday;
698c2ecf20Sopenharmony_ci	spinlock_t lock;
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
758c2ecf20Sopenharmony_ci	void __iomem *ioaddr = pdata->ioaddr;
768c2ecf20Sopenharmony_ci	u8 flags;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	flags = readb(pdata->ioaddr + RTC_FLAGS);
798c2ecf20Sopenharmony_ci	writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	writeb(bin2bcd(tm->tm_year % 100), ioaddr + RTC_YEAR);
828c2ecf20Sopenharmony_ci	writeb(bin2bcd(tm->tm_mon + 1), ioaddr + RTC_MONTH);
838c2ecf20Sopenharmony_ci	writeb(bin2bcd(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
848c2ecf20Sopenharmony_ci	writeb(bin2bcd(tm->tm_mday), ioaddr + RTC_DATE);
858c2ecf20Sopenharmony_ci	writeb(bin2bcd(tm->tm_hour), ioaddr + RTC_HOURS);
868c2ecf20Sopenharmony_ci	writeb(bin2bcd(tm->tm_min), ioaddr + RTC_MINUTES);
878c2ecf20Sopenharmony_ci	writeb(bin2bcd(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
888c2ecf20Sopenharmony_ci	writeb(bin2bcd((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
918c2ecf20Sopenharmony_ci	return 0;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
978c2ecf20Sopenharmony_ci	void __iomem *ioaddr = pdata->ioaddr;
988c2ecf20Sopenharmony_ci	unsigned int year, month, day, hour, minute, second, week;
998c2ecf20Sopenharmony_ci	unsigned int century;
1008c2ecf20Sopenharmony_ci	u8 flags;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/* give enough time to update RTC in case of continuous read */
1038c2ecf20Sopenharmony_ci	if (pdata->last_jiffies == jiffies)
1048c2ecf20Sopenharmony_ci		msleep(1);
1058c2ecf20Sopenharmony_ci	pdata->last_jiffies = jiffies;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	flags = readb(pdata->ioaddr + RTC_FLAGS);
1088c2ecf20Sopenharmony_ci	writeb(flags | RTC_READ, ioaddr + RTC_FLAGS);
1098c2ecf20Sopenharmony_ci	second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
1108c2ecf20Sopenharmony_ci	minute = readb(ioaddr + RTC_MINUTES);
1118c2ecf20Sopenharmony_ci	hour = readb(ioaddr + RTC_HOURS);
1128c2ecf20Sopenharmony_ci	day = readb(ioaddr + RTC_DATE);
1138c2ecf20Sopenharmony_ci	week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
1148c2ecf20Sopenharmony_ci	month = readb(ioaddr + RTC_MONTH);
1158c2ecf20Sopenharmony_ci	year = readb(ioaddr + RTC_YEAR);
1168c2ecf20Sopenharmony_ci	century = readb(ioaddr + RTC_CENTURY);
1178c2ecf20Sopenharmony_ci	writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS);
1188c2ecf20Sopenharmony_ci	tm->tm_sec = bcd2bin(second);
1198c2ecf20Sopenharmony_ci	tm->tm_min = bcd2bin(minute);
1208c2ecf20Sopenharmony_ci	tm->tm_hour = bcd2bin(hour);
1218c2ecf20Sopenharmony_ci	tm->tm_mday = bcd2bin(day);
1228c2ecf20Sopenharmony_ci	tm->tm_wday = bcd2bin(week);
1238c2ecf20Sopenharmony_ci	tm->tm_mon = bcd2bin(month) - 1;
1248c2ecf20Sopenharmony_ci	/* year is 1900 + tm->tm_year */
1258c2ecf20Sopenharmony_ci	tm->tm_year = bcd2bin(year) + bcd2bin(century) * 100 - 1900;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return 0;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	void __iomem *ioaddr = pdata->ioaddr;
1338c2ecf20Sopenharmony_ci	unsigned long irqflags;
1348c2ecf20Sopenharmony_ci	u8 flags;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pdata->lock, irqflags);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	flags = readb(ioaddr + RTC_FLAGS);
1398c2ecf20Sopenharmony_ci	writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
1428c2ecf20Sopenharmony_ci	       0x80 : bin2bcd(pdata->alrm_mday),
1438c2ecf20Sopenharmony_ci	       ioaddr + RTC_DATE_ALARM);
1448c2ecf20Sopenharmony_ci	writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
1458c2ecf20Sopenharmony_ci	       0x80 : bin2bcd(pdata->alrm_hour),
1468c2ecf20Sopenharmony_ci	       ioaddr + RTC_HOURS_ALARM);
1478c2ecf20Sopenharmony_ci	writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
1488c2ecf20Sopenharmony_ci	       0x80 : bin2bcd(pdata->alrm_min),
1498c2ecf20Sopenharmony_ci	       ioaddr + RTC_MINUTES_ALARM);
1508c2ecf20Sopenharmony_ci	writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
1518c2ecf20Sopenharmony_ci	       0x80 : bin2bcd(pdata->alrm_sec),
1528c2ecf20Sopenharmony_ci	       ioaddr + RTC_SECONDS_ALARM);
1538c2ecf20Sopenharmony_ci	writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
1548c2ecf20Sopenharmony_ci	readb(ioaddr + RTC_FLAGS);	/* clear interrupts */
1558c2ecf20Sopenharmony_ci	writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
1568c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pdata->lock, irqflags);
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (pdata->irq <= 0)
1648c2ecf20Sopenharmony_ci		return -EINVAL;
1658c2ecf20Sopenharmony_ci	pdata->alrm_mday = alrm->time.tm_mday;
1668c2ecf20Sopenharmony_ci	pdata->alrm_hour = alrm->time.tm_hour;
1678c2ecf20Sopenharmony_ci	pdata->alrm_min = alrm->time.tm_min;
1688c2ecf20Sopenharmony_ci	pdata->alrm_sec = alrm->time.tm_sec;
1698c2ecf20Sopenharmony_ci	if (alrm->enabled)
1708c2ecf20Sopenharmony_ci		pdata->irqen |= RTC_AF;
1718c2ecf20Sopenharmony_ci	stk17ta8_rtc_update_alarm(pdata);
1728c2ecf20Sopenharmony_ci	return 0;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (pdata->irq <= 0)
1808c2ecf20Sopenharmony_ci		return -EINVAL;
1818c2ecf20Sopenharmony_ci	alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
1828c2ecf20Sopenharmony_ci	alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
1838c2ecf20Sopenharmony_ci	alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
1848c2ecf20Sopenharmony_ci	alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
1858c2ecf20Sopenharmony_ci	alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
1868c2ecf20Sopenharmony_ci	return 0;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct platform_device *pdev = dev_id;
1928c2ecf20Sopenharmony_ci	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
1938c2ecf20Sopenharmony_ci	void __iomem *ioaddr = pdata->ioaddr;
1948c2ecf20Sopenharmony_ci	unsigned long events = 0;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	spin_lock(&pdata->lock);
1978c2ecf20Sopenharmony_ci	/* read and clear interrupt */
1988c2ecf20Sopenharmony_ci	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) {
1998c2ecf20Sopenharmony_ci		events = RTC_IRQF;
2008c2ecf20Sopenharmony_ci		if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
2018c2ecf20Sopenharmony_ci			events |= RTC_UF;
2028c2ecf20Sopenharmony_ci		else
2038c2ecf20Sopenharmony_ci			events |= RTC_AF;
2048c2ecf20Sopenharmony_ci		rtc_update_irq(pdata->rtc, 1, events);
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci	spin_unlock(&pdata->lock);
2078c2ecf20Sopenharmony_ci	return events ? IRQ_HANDLED : IRQ_NONE;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic int stk17ta8_rtc_alarm_irq_enable(struct device *dev,
2118c2ecf20Sopenharmony_ci	unsigned int enabled)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (pdata->irq <= 0)
2168c2ecf20Sopenharmony_ci		return -EINVAL;
2178c2ecf20Sopenharmony_ci	if (enabled)
2188c2ecf20Sopenharmony_ci		pdata->irqen |= RTC_AF;
2198c2ecf20Sopenharmony_ci	else
2208c2ecf20Sopenharmony_ci		pdata->irqen &= ~RTC_AF;
2218c2ecf20Sopenharmony_ci	stk17ta8_rtc_update_alarm(pdata);
2228c2ecf20Sopenharmony_ci	return 0;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic const struct rtc_class_ops stk17ta8_rtc_ops = {
2268c2ecf20Sopenharmony_ci	.read_time		= stk17ta8_rtc_read_time,
2278c2ecf20Sopenharmony_ci	.set_time		= stk17ta8_rtc_set_time,
2288c2ecf20Sopenharmony_ci	.read_alarm		= stk17ta8_rtc_read_alarm,
2298c2ecf20Sopenharmony_ci	.set_alarm		= stk17ta8_rtc_set_alarm,
2308c2ecf20Sopenharmony_ci	.alarm_irq_enable	= stk17ta8_rtc_alarm_irq_enable,
2318c2ecf20Sopenharmony_ci};
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic int stk17ta8_nvram_read(void *priv, unsigned int pos, void *val,
2348c2ecf20Sopenharmony_ci			       size_t bytes)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	struct rtc_plat_data *pdata = priv;
2378c2ecf20Sopenharmony_ci	void __iomem *ioaddr = pdata->ioaddr;
2388c2ecf20Sopenharmony_ci	u8 *buf = val;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	for (; bytes; bytes--)
2418c2ecf20Sopenharmony_ci		*buf++ = readb(ioaddr + pos++);
2428c2ecf20Sopenharmony_ci	return 0;
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int stk17ta8_nvram_write(void *priv, unsigned int pos, void *val,
2468c2ecf20Sopenharmony_ci				size_t bytes)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	struct rtc_plat_data *pdata = priv;
2498c2ecf20Sopenharmony_ci	void __iomem *ioaddr = pdata->ioaddr;
2508c2ecf20Sopenharmony_ci	u8 *buf = val;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	for (; bytes; bytes--)
2538c2ecf20Sopenharmony_ci		writeb(*buf++, ioaddr + pos++);
2548c2ecf20Sopenharmony_ci	return 0;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic int stk17ta8_rtc_probe(struct platform_device *pdev)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	unsigned int cal;
2608c2ecf20Sopenharmony_ci	unsigned int flags;
2618c2ecf20Sopenharmony_ci	struct rtc_plat_data *pdata;
2628c2ecf20Sopenharmony_ci	void __iomem *ioaddr;
2638c2ecf20Sopenharmony_ci	int ret = 0;
2648c2ecf20Sopenharmony_ci	struct nvmem_config nvmem_cfg = {
2658c2ecf20Sopenharmony_ci		.name = "stk17ta8_nvram",
2668c2ecf20Sopenharmony_ci		.word_size = 1,
2678c2ecf20Sopenharmony_ci		.stride = 1,
2688c2ecf20Sopenharmony_ci		.size = RTC_OFFSET,
2698c2ecf20Sopenharmony_ci		.reg_read = stk17ta8_nvram_read,
2708c2ecf20Sopenharmony_ci		.reg_write = stk17ta8_nvram_write,
2718c2ecf20Sopenharmony_ci	};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
2748c2ecf20Sopenharmony_ci	if (!pdata)
2758c2ecf20Sopenharmony_ci		return -ENOMEM;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	ioaddr = devm_platform_ioremap_resource(pdev, 0);
2788c2ecf20Sopenharmony_ci	if (IS_ERR(ioaddr))
2798c2ecf20Sopenharmony_ci		return PTR_ERR(ioaddr);
2808c2ecf20Sopenharmony_ci	pdata->ioaddr = ioaddr;
2818c2ecf20Sopenharmony_ci	pdata->irq = platform_get_irq(pdev, 0);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* turn RTC on if it was not on */
2848c2ecf20Sopenharmony_ci	cal = readb(ioaddr + RTC_CALIBRATION);
2858c2ecf20Sopenharmony_ci	if (cal & RTC_STOP) {
2868c2ecf20Sopenharmony_ci		cal &= RTC_CAL_MASK;
2878c2ecf20Sopenharmony_ci		flags = readb(ioaddr + RTC_FLAGS);
2888c2ecf20Sopenharmony_ci		writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
2898c2ecf20Sopenharmony_ci		writeb(cal, ioaddr + RTC_CALIBRATION);
2908c2ecf20Sopenharmony_ci		writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)
2938c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev, "voltage-low detected.\n");
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	spin_lock_init(&pdata->lock);
2968c2ecf20Sopenharmony_ci	pdata->last_jiffies = jiffies;
2978c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, pdata);
2988c2ecf20Sopenharmony_ci	if (pdata->irq > 0) {
2998c2ecf20Sopenharmony_ci		writeb(0, ioaddr + RTC_INTERRUPTS);
3008c2ecf20Sopenharmony_ci		if (devm_request_irq(&pdev->dev, pdata->irq,
3018c2ecf20Sopenharmony_ci				stk17ta8_rtc_interrupt,
3028c2ecf20Sopenharmony_ci				IRQF_SHARED,
3038c2ecf20Sopenharmony_ci				pdev->name, pdev) < 0) {
3048c2ecf20Sopenharmony_ci			dev_warn(&pdev->dev, "interrupt not available.\n");
3058c2ecf20Sopenharmony_ci			pdata->irq = 0;
3068c2ecf20Sopenharmony_ci		}
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
3108c2ecf20Sopenharmony_ci	if (IS_ERR(pdata->rtc))
3118c2ecf20Sopenharmony_ci		return PTR_ERR(pdata->rtc);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	pdata->rtc->ops = &stk17ta8_rtc_ops;
3148c2ecf20Sopenharmony_ci	pdata->rtc->nvram_old_abi = true;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	nvmem_cfg.priv = pdata;
3178c2ecf20Sopenharmony_ci	ret = rtc_nvmem_register(pdata->rtc, &nvmem_cfg);
3188c2ecf20Sopenharmony_ci	if (ret)
3198c2ecf20Sopenharmony_ci		return ret;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return rtc_register_device(pdata->rtc);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci/* work with hotplug and coldplug */
3258c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:stk17ta8");
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic struct platform_driver stk17ta8_rtc_driver = {
3288c2ecf20Sopenharmony_ci	.probe		= stk17ta8_rtc_probe,
3298c2ecf20Sopenharmony_ci	.driver		= {
3308c2ecf20Sopenharmony_ci		.name	= "stk17ta8",
3318c2ecf20Sopenharmony_ci	},
3328c2ecf20Sopenharmony_ci};
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cimodule_platform_driver(stk17ta8_rtc_driver);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Thomas Hommel <thomas.hommel@ge.com>");
3378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
3388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
339