11c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König/* 21c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * Real Time Clock driver for Freescale MC13XXX PMIC 31c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * 41c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * (C) 2009 Sascha Hauer, Pengutronix 51c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * (C) 2009 Uwe Kleine-Koenig, Pengutronix 61c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * 71c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * This program is free software; you can redistribute it and/or modify 81c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * it under the terms of the GNU General Public License version 2 as 91c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * published by the Free Software Foundation. 101c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König */ 111c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 121c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#include <linux/mfd/mc13xxx.h> 131c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#include <linux/platform_device.h> 141c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#include <linux/kernel.h> 151c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#include <linux/module.h> 161c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#include <linux/slab.h> 171c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#include <linux/rtc.h> 181c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 191c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#define DRIVER_NAME "mc13xxx-rtc" 201c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 211c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#define MC13XXX_RTCTOD 20 221c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#define MC13XXX_RTCTODA 21 231c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#define MC13XXX_RTCDAY 22 241c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König#define MC13XXX_RTCDAYA 23 251c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 266a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan#define SEC_PER_DAY (24 * 60 * 60) 276a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan 281c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstruct mc13xxx_rtc { 291c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct rtc_device *rtc; 301c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx *mc13xxx; 311c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König int valid; 321c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König}; 331c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 341c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic int mc13xxx_rtc_irq_enable_unlocked(struct device *dev, 351c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König unsigned int enabled, int irq) 361c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 371c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = dev_get_drvdata(dev); 381c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König int (*func)(struct mc13xxx *mc13xxx, int irq); 391c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 401c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (!priv->valid) 411c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return -ENODATA; 421c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 431c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König func = enabled ? mc13xxx_irq_unmask : mc13xxx_irq_mask; 441c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return func(priv->mc13xxx, irq); 451c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 461c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 472fb004a9b00e34908e59a1c1c5770910690a7588Alexander Shiyanstatic int mc13xxx_rtc_alarm_irq_enable(struct device *dev, 482fb004a9b00e34908e59a1c1c5770910690a7588Alexander Shiyan unsigned int enabled) 491c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 501c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = dev_get_drvdata(dev); 511c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König int ret; 521c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 531c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_lock(priv->mc13xxx); 541c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 552fb004a9b00e34908e59a1c1c5770910690a7588Alexander Shiyan ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, MC13XXX_IRQ_TODA); 561c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 571c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_unlock(priv->mc13xxx); 581c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 591c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return ret; 601c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 611c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 621c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) 631c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 641c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = dev_get_drvdata(dev); 651c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König unsigned int seconds, days1, days2; 661c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 6712de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan if (!priv->valid) 6812de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan return -ENODATA; 691c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 706a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan do { 716a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan int ret; 721c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 736a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1); 746a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan if (ret) 756a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan return ret; 761c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 776a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds); 786a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan if (ret) 796a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan return ret; 801c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 816a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2); 826a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan if (ret) 836a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan return ret; 846a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan } while (days1 != days2); 851c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 866a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan rtc_time_to_tm(days1 * SEC_PER_DAY + seconds, tm); 871c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 881c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return rtc_valid_tm(tm); 891c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 901c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 911c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs) 921c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 931c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = dev_get_drvdata(dev); 941c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König unsigned int seconds, days; 951c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König unsigned int alarmseconds; 961c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König int ret; 971c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 986a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan seconds = secs % SEC_PER_DAY; 996a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan days = secs / SEC_PER_DAY; 1001c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1011c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_lock(priv->mc13xxx); 1021c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1031c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König /* 1041c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * temporarily invalidate alarm to prevent triggering it when the day is 1051c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * already updated while the time isn't yet. 1061c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König */ 1071c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &alarmseconds); 1081c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 1091c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 1101c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1116a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan if (alarmseconds < SEC_PER_DAY) { 1121c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_write(priv->mc13xxx, 1131c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König MC13XXX_RTCTODA, 0x1ffff); 1141c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 1151c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 1161c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König } 1171c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1181c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König /* 1191c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * write seconds=0 to prevent a day switch between writing days 1201c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König * and seconds below 1211c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König */ 1221c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, 0); 1231c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 1241c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 1251c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1261c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAY, days); 1271c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 1281c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 1291c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1301c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, seconds); 1311c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 1321c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 1331c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1341c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König /* restore alarm */ 1356a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan if (alarmseconds < SEC_PER_DAY) { 1361c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_write(priv->mc13xxx, 1371c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König MC13XXX_RTCTODA, alarmseconds); 1381c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 1391c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 1401c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König } 1411c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 14212de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan if (!priv->valid) { 14312de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST); 14412de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan if (unlikely(ret)) 14512de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan goto out; 14612de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan 14712de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST); 14812de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan } 1491c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1501c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königout: 1511c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König priv->valid = !ret; 1521c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1531c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_unlock(priv->mc13xxx); 1541c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1551c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return ret; 1561c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 1571c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1581c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) 1591c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 1601c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = dev_get_drvdata(dev); 1611c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König unsigned seconds, days; 1621c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König unsigned long s1970; 1631c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König int enabled, pending; 1641c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König int ret; 1651c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1661c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_lock(priv->mc13xxx); 1671c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1681c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds); 1691c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 1701c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 1716a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan if (seconds >= SEC_PER_DAY) { 1721c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = -ENODATA; 1731c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 1741c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König } 1751c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1761c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days); 1771c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 1781c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 1791c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1801c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_irq_status(priv->mc13xxx, MC13XXX_IRQ_TODA, 1811c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König &enabled, &pending); 1821c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1831c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königout: 1841c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_unlock(priv->mc13xxx); 1851c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1861c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (ret) 1871c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return ret; 1881c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1891c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König alarm->enabled = enabled; 1901c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König alarm->pending = pending; 1911c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1926a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan s1970 = days * SEC_PER_DAY + seconds; 1931c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1941c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König rtc_time_to_tm(s1970, &alarm->time); 1951c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König dev_dbg(dev, "%s: %lu\n", __func__, s1970); 1961c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 1971c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return 0; 1981c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 1991c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2001c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) 2011c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 2021c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = dev_get_drvdata(dev); 2031c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König unsigned long s1970; 2041c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König unsigned seconds, days; 2051c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König int ret; 2061c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2071c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_lock(priv->mc13xxx); 2081c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2091c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König /* disable alarm to prevent false triggering */ 2101c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, 0x1ffff); 2111c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 2121c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 2131c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2141c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TODA); 2151c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 2161c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 2171c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2181c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = rtc_tm_to_time(&alarm->time, &s1970); 2191c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 2201c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 2211c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2221c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König dev_dbg(dev, "%s: o%2.s %lu\n", __func__, alarm->enabled ? "n" : "ff", 2231c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König s1970); 2241c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2251c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_rtc_irq_enable_unlocked(dev, alarm->enabled, 2261c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König MC13XXX_IRQ_TODA); 2271c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 2281c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 2291c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2306a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan seconds = s1970 % SEC_PER_DAY; 2316a2b342228b98432a585c83d59ed6aa0620be7c4Alexander Shiyan days = s1970 / SEC_PER_DAY; 2321c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2331c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days); 2341c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (unlikely(ret)) 2351c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König goto out; 2361c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2371c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, seconds); 2381c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2391c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königout: 2401c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_unlock(priv->mc13xxx); 2411c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2421c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return ret; 2431c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 2441c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2451c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev) 2461c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 2471c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = dev; 2481c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx *mc13xxx = priv->mc13xxx; 2491c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2501c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF); 2511c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2521c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_irq_ack(mc13xxx, irq); 2531c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2541c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return IRQ_HANDLED; 2551c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 2561c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2571c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev) 2581c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 2591c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = dev; 2601c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx *mc13xxx = priv->mc13xxx; 2611c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2621c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); 2631c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2641c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_irq_ack(mc13xxx, irq); 2651c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2661c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return IRQ_HANDLED; 2671c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 2681c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2691c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic const struct rtc_class_ops mc13xxx_rtc_ops = { 2701c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .read_time = mc13xxx_rtc_read_time, 2711c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .set_mmss = mc13xxx_rtc_set_mmss, 2721c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .read_alarm = mc13xxx_rtc_read_alarm, 2731c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .set_alarm = mc13xxx_rtc_set_alarm, 2741c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable, 2751c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König}; 2761c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2771c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev) 2781c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 2791c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = dev; 2801c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx *mc13xxx = priv->mc13xxx; 2811c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2821c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König priv->valid = 0; 2831c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2841c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_irq_mask(mc13xxx, irq); 2851c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2861c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return IRQ_HANDLED; 2871c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 2881c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 289db5cf8d1ac4ac3fa06d89345154ce20068aeb097Uwe Kleine-Königstatic int __init mc13xxx_rtc_probe(struct platform_device *pdev) 2901c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 2911c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König int ret; 2921c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv; 2931c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx *mc13xxx; 2941c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 295a379fd2458d78d3286c8103aa479839b073c89feJingoo Han priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 2961c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (!priv) 2971c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return -ENOMEM; 2981c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 2991c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx = dev_get_drvdata(pdev->dev.parent); 3001c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König priv->mc13xxx = mc13xxx; 30112de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan priv->valid = 1; 3021c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3031c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König platform_set_drvdata(pdev, priv); 3041c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3051c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_lock(mc13xxx); 3061c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 30712de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_RTCRST); 30812de362108d5ec24cce1bbe520570dc8fdccca9cAlexander Shiyan 3091c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST, 3101c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_rtc_reset_handler, DRIVER_NAME, priv); 3111c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (ret) 3125ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan goto err_irq_request; 3131c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 314fb1bd9a22da3d0f2436ffa95fdc0382b89659288Alexander Shiyan ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_1HZ, 3151c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_rtc_update_handler, DRIVER_NAME, priv); 3161c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König if (ret) 3175ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan goto err_irq_request; 3181c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3191c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA, 3201c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv); 3215ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan if (ret) 3225ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan goto err_irq_request; 3231c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3245ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan mc13xxx_unlock(mc13xxx); 3255ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan 3265ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan priv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, 3275ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan &mc13xxx_rtc_ops, THIS_MODULE); 3281c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3295ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan return 0; 3305ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan 3315ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyanerr_irq_request: 3325ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); 3335ab9a52a3af613b74a7cda033c1623c7913c50d9Alexander Shiyan mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv); 334589e501439f9866b4bc415743b0ae0bb9a461c69Alexander Shiyan mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); 3351c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 336589e501439f9866b4bc415743b0ae0bb9a461c69Alexander Shiyan mc13xxx_unlock(mc13xxx); 3371c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3381c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return ret; 3391c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 3401c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 34177bf2ea8de78ce7dd842409a847b888e720f62d8Alexander Shiyanstatic int mc13xxx_rtc_remove(struct platform_device *pdev) 3421c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König{ 3431c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König struct mc13xxx_rtc *priv = platform_get_drvdata(pdev); 3441c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3451c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_lock(priv->mc13xxx); 3461c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3471c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TODA, priv); 3481c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_1HZ, priv); 3491c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv); 3501c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3511c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König mc13xxx_unlock(priv->mc13xxx); 3521c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3531c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König return 0; 3541c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König} 3551c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 356a46481d7af1e6c59c03f3ddac400d9054f804952Axel Linstatic const struct platform_device_id mc13xxx_rtc_idtable[] = { 3571c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König { 3581c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .name = "mc13783-rtc", 3591c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König }, { 3601c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .name = "mc13892-rtc", 36119a1ac505d5f3545ebc5b0a195d65cef4da94bb5Uwe Kleine-König }, { 36219a1ac505d5f3545ebc5b0a195d65cef4da94bb5Uwe Kleine-König .name = "mc34708-rtc", 3631c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König }, 3640f636fc16f80fe64261ce39440e49a259ff2b0daUwe Kleine-König { /* sentinel */ } 3651c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König}; 3660f636fc16f80fe64261ce39440e49a259ff2b0daUwe Kleine-KönigMODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable); 3671c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3681c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-Königstatic struct platform_driver mc13xxx_rtc_driver = { 3691c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .id_table = mc13xxx_rtc_idtable, 37077bf2ea8de78ce7dd842409a847b888e720f62d8Alexander Shiyan .remove = mc13xxx_rtc_remove, 3711c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .driver = { 3721c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .name = DRIVER_NAME, 3731c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König .owner = THIS_MODULE, 3741c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König }, 3751c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König}; 3761c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 37709fb7ad15aa62116f96e0f7b62c7723e636786f1Jingoo Hanmodule_platform_driver_probe(mc13xxx_rtc_driver, &mc13xxx_rtc_probe); 3781c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-König 3791c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-KönigMODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 3801c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-KönigMODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC"); 3811c97872b80691f6bd3e46ec431a0d59dc75cb8daUwe Kleine-KönigMODULE_LICENSE("GPL v2"); 382