brintos

brintos / linux-shallow public Read only

0
0
Text · 8.6 KiB · 76ad703 Raw
361 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2010 NXP Semiconductors4 */5 6#include <linux/kernel.h>7#include <linux/module.h>8#include <linux/init.h>9#include <linux/platform_device.h>10#include <linux/spinlock.h>11#include <linux/rtc.h>12#include <linux/slab.h>13#include <linux/io.h>14#include <linux/of.h>15 16/*17 * Clock and Power control register offsets18 */19#define LPC32XX_RTC_UCOUNT		0x0020#define LPC32XX_RTC_DCOUNT		0x0421#define LPC32XX_RTC_MATCH0		0x0822#define LPC32XX_RTC_MATCH1		0x0C23#define LPC32XX_RTC_CTRL		0x1024#define LPC32XX_RTC_INTSTAT		0x1425#define LPC32XX_RTC_KEY			0x1826#define LPC32XX_RTC_SRAM		0x8027 28#define LPC32XX_RTC_CTRL_MATCH0		(1 << 0)29#define LPC32XX_RTC_CTRL_MATCH1		(1 << 1)30#define LPC32XX_RTC_CTRL_ONSW_MATCH0	(1 << 2)31#define LPC32XX_RTC_CTRL_ONSW_MATCH1	(1 << 3)32#define LPC32XX_RTC_CTRL_SW_RESET	(1 << 4)33#define LPC32XX_RTC_CTRL_CNTR_DIS	(1 << 6)34#define LPC32XX_RTC_CTRL_ONSW_FORCE_HI	(1 << 7)35 36#define LPC32XX_RTC_INTSTAT_MATCH0	(1 << 0)37#define LPC32XX_RTC_INTSTAT_MATCH1	(1 << 1)38#define LPC32XX_RTC_INTSTAT_ONSW	(1 << 2)39 40#define LPC32XX_RTC_KEY_ONSW_LOADVAL	0xB5C13F2741 42#define rtc_readl(dev, reg) \43	__raw_readl((dev)->rtc_base + (reg))44#define rtc_writel(dev, reg, val) \45	__raw_writel((val), (dev)->rtc_base + (reg))46 47struct lpc32xx_rtc {48	void __iomem *rtc_base;49	int irq;50	unsigned char alarm_enabled;51	struct rtc_device *rtc;52	spinlock_t lock;53};54 55static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time)56{57	unsigned long elapsed_sec;58	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);59 60	elapsed_sec = rtc_readl(rtc, LPC32XX_RTC_UCOUNT);61	rtc_time64_to_tm(elapsed_sec, time);62 63	return 0;64}65 66static int lpc32xx_rtc_set_time(struct device *dev, struct rtc_time *time)67{68	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);69	u32 secs = rtc_tm_to_time64(time);70	u32 tmp;71 72	spin_lock_irq(&rtc->lock);73 74	/* RTC must be disabled during count update */75	tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);76	rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | LPC32XX_RTC_CTRL_CNTR_DIS);77	rtc_writel(rtc, LPC32XX_RTC_UCOUNT, secs);78	rtc_writel(rtc, LPC32XX_RTC_DCOUNT, 0xFFFFFFFF - secs);79	rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp &= ~LPC32XX_RTC_CTRL_CNTR_DIS);80 81	spin_unlock_irq(&rtc->lock);82 83	return 0;84}85 86static int lpc32xx_rtc_read_alarm(struct device *dev,87	struct rtc_wkalrm *wkalrm)88{89	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);90 91	rtc_time64_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time);92	wkalrm->enabled = rtc->alarm_enabled;93	wkalrm->pending = !!(rtc_readl(rtc, LPC32XX_RTC_INTSTAT) &94		LPC32XX_RTC_INTSTAT_MATCH0);95 96	return rtc_valid_tm(&wkalrm->time);97}98 99static int lpc32xx_rtc_set_alarm(struct device *dev,100	struct rtc_wkalrm *wkalrm)101{102	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);103	unsigned long alarmsecs;104	u32 tmp;105 106	alarmsecs = rtc_tm_to_time64(&wkalrm->time);107 108	spin_lock_irq(&rtc->lock);109 110	/* Disable alarm during update */111	tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);112	rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp & ~LPC32XX_RTC_CTRL_MATCH0);113 114	rtc_writel(rtc, LPC32XX_RTC_MATCH0, alarmsecs);115 116	rtc->alarm_enabled = wkalrm->enabled;117	if (wkalrm->enabled) {118		rtc_writel(rtc, LPC32XX_RTC_INTSTAT,119			   LPC32XX_RTC_INTSTAT_MATCH0);120		rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp |121			   LPC32XX_RTC_CTRL_MATCH0);122	}123 124	spin_unlock_irq(&rtc->lock);125 126	return 0;127}128 129static int lpc32xx_rtc_alarm_irq_enable(struct device *dev,130	unsigned int enabled)131{132	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);133	u32 tmp;134 135	spin_lock_irq(&rtc->lock);136	tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);137 138	if (enabled) {139		rtc->alarm_enabled = 1;140		tmp |= LPC32XX_RTC_CTRL_MATCH0;141	} else {142		rtc->alarm_enabled = 0;143		tmp &= ~LPC32XX_RTC_CTRL_MATCH0;144	}145 146	rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);147	spin_unlock_irq(&rtc->lock);148 149	return 0;150}151 152static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev)153{154	struct lpc32xx_rtc *rtc = dev;155 156	spin_lock(&rtc->lock);157 158	/* Disable alarm interrupt */159	rtc_writel(rtc, LPC32XX_RTC_CTRL,160		rtc_readl(rtc, LPC32XX_RTC_CTRL) &161			  ~LPC32XX_RTC_CTRL_MATCH0);162	rtc->alarm_enabled = 0;163 164	/*165	 * Write a large value to the match value so the RTC won't166	 * keep firing the match status167	 */168	rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);169	rtc_writel(rtc, LPC32XX_RTC_INTSTAT, LPC32XX_RTC_INTSTAT_MATCH0);170 171	spin_unlock(&rtc->lock);172 173	rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);174 175	return IRQ_HANDLED;176}177 178static const struct rtc_class_ops lpc32xx_rtc_ops = {179	.read_time		= lpc32xx_rtc_read_time,180	.set_time		= lpc32xx_rtc_set_time,181	.read_alarm		= lpc32xx_rtc_read_alarm,182	.set_alarm		= lpc32xx_rtc_set_alarm,183	.alarm_irq_enable	= lpc32xx_rtc_alarm_irq_enable,184};185 186static int lpc32xx_rtc_probe(struct platform_device *pdev)187{188	struct lpc32xx_rtc *rtc;189	int err;190	u32 tmp;191 192	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);193	if (unlikely(!rtc))194		return -ENOMEM;195 196	rtc->rtc_base = devm_platform_ioremap_resource(pdev, 0);197	if (IS_ERR(rtc->rtc_base))198		return PTR_ERR(rtc->rtc_base);199 200	spin_lock_init(&rtc->lock);201 202	/*203	 * The RTC is on a separate power domain and can keep it's state204	 * across a chip power cycle. If the RTC has never been previously205	 * setup, then set it up now for the first time.206	 */207	tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);208	if (rtc_readl(rtc, LPC32XX_RTC_KEY) != LPC32XX_RTC_KEY_ONSW_LOADVAL) {209		tmp &= ~(LPC32XX_RTC_CTRL_SW_RESET |210			LPC32XX_RTC_CTRL_CNTR_DIS |211			LPC32XX_RTC_CTRL_MATCH0 |212			LPC32XX_RTC_CTRL_MATCH1 |213			LPC32XX_RTC_CTRL_ONSW_MATCH0 |214			LPC32XX_RTC_CTRL_ONSW_MATCH1 |215			LPC32XX_RTC_CTRL_ONSW_FORCE_HI);216		rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);217 218		/* Clear latched interrupt states */219		rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);220		rtc_writel(rtc, LPC32XX_RTC_INTSTAT,221			   LPC32XX_RTC_INTSTAT_MATCH0 |222			   LPC32XX_RTC_INTSTAT_MATCH1 |223			   LPC32XX_RTC_INTSTAT_ONSW);224 225		/* Write key value to RTC so it won't reload on reset */226		rtc_writel(rtc, LPC32XX_RTC_KEY,227			   LPC32XX_RTC_KEY_ONSW_LOADVAL);228	} else {229		rtc_writel(rtc, LPC32XX_RTC_CTRL,230			   tmp & ~LPC32XX_RTC_CTRL_MATCH0);231	}232 233	platform_set_drvdata(pdev, rtc);234 235	rtc->rtc = devm_rtc_allocate_device(&pdev->dev);236	if (IS_ERR(rtc->rtc))237		return PTR_ERR(rtc->rtc);238 239	rtc->rtc->ops = &lpc32xx_rtc_ops;240	rtc->rtc->range_max = U32_MAX;241 242	err = devm_rtc_register_device(rtc->rtc);243	if (err)244		return err;245 246	/*247	 * IRQ is enabled after device registration in case alarm IRQ248	 * is pending upon suspend exit.249	 */250	rtc->irq = platform_get_irq(pdev, 0);251	if (rtc->irq < 0) {252		dev_warn(&pdev->dev, "Can't get interrupt resource\n");253	} else {254		if (devm_request_irq(&pdev->dev, rtc->irq,255				     lpc32xx_rtc_alarm_interrupt,256				     0, pdev->name, rtc) < 0) {257			dev_warn(&pdev->dev, "Can't request interrupt.\n");258			rtc->irq = -1;259		} else {260			device_init_wakeup(&pdev->dev, 1);261		}262	}263 264	return 0;265}266 267#ifdef CONFIG_PM268static int lpc32xx_rtc_suspend(struct device *dev)269{270	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);271 272	if (rtc->irq >= 0) {273		if (device_may_wakeup(dev))274			enable_irq_wake(rtc->irq);275		else276			disable_irq_wake(rtc->irq);277	}278 279	return 0;280}281 282static int lpc32xx_rtc_resume(struct device *dev)283{284	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);285 286	if (rtc->irq >= 0 && device_may_wakeup(dev))287		disable_irq_wake(rtc->irq);288 289	return 0;290}291 292/* Unconditionally disable the alarm */293static int lpc32xx_rtc_freeze(struct device *dev)294{295	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);296 297	spin_lock_irq(&rtc->lock);298 299	rtc_writel(rtc, LPC32XX_RTC_CTRL,300		rtc_readl(rtc, LPC32XX_RTC_CTRL) &301			  ~LPC32XX_RTC_CTRL_MATCH0);302 303	spin_unlock_irq(&rtc->lock);304 305	return 0;306}307 308static int lpc32xx_rtc_thaw(struct device *dev)309{310	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);311 312	if (rtc->alarm_enabled) {313		spin_lock_irq(&rtc->lock);314 315		rtc_writel(rtc, LPC32XX_RTC_CTRL,316			   rtc_readl(rtc, LPC32XX_RTC_CTRL) |317			   LPC32XX_RTC_CTRL_MATCH0);318 319		spin_unlock_irq(&rtc->lock);320	}321 322	return 0;323}324 325static const struct dev_pm_ops lpc32xx_rtc_pm_ops = {326	.suspend = lpc32xx_rtc_suspend,327	.resume = lpc32xx_rtc_resume,328	.freeze = lpc32xx_rtc_freeze,329	.thaw = lpc32xx_rtc_thaw,330	.restore = lpc32xx_rtc_resume331};332 333#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops)334#else335#define LPC32XX_RTC_PM_OPS NULL336#endif337 338#ifdef CONFIG_OF339static const struct of_device_id lpc32xx_rtc_match[] = {340	{ .compatible = "nxp,lpc3220-rtc" },341	{ }342};343MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match);344#endif345 346static struct platform_driver lpc32xx_rtc_driver = {347	.probe		= lpc32xx_rtc_probe,348	.driver = {349		.name	= "rtc-lpc32xx",350		.pm	= LPC32XX_RTC_PM_OPS,351		.of_match_table = of_match_ptr(lpc32xx_rtc_match),352	},353};354 355module_platform_driver(lpc32xx_rtc_driver);356 357MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com");358MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC");359MODULE_LICENSE("GPL");360MODULE_ALIAS("platform:rtc-lpc32xx");361