brintos

brintos / linux-shallow public Read only

0
0
Text · 10.4 KiB · 4ca60b5 Raw
413 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Copyright 2019 Cadence5 *6 * Authors:7 *  Jan Kotas <jank@cadence.com>8 */9 10#include <linux/module.h>11#include <linux/platform_device.h>12#include <linux/of.h>13#include <linux/io.h>14#include <linux/rtc.h>15#include <linux/clk.h>16#include <linux/bcd.h>17#include <linux/bitfield.h>18#include <linux/interrupt.h>19#include <linux/pm_wakeirq.h>20 21/* Registers */22#define CDNS_RTC_CTLR		0x0023#define CDNS_RTC_HMR		0x0424#define CDNS_RTC_TIMR		0x0825#define CDNS_RTC_CALR		0x0C26#define CDNS_RTC_TIMAR		0x1027#define CDNS_RTC_CALAR		0x1428#define CDNS_RTC_AENR		0x1829#define CDNS_RTC_EFLR		0x1C30#define CDNS_RTC_IENR		0x2031#define CDNS_RTC_IDISR		0x2432#define CDNS_RTC_IMSKR		0x2833#define CDNS_RTC_STSR		0x2C34#define CDNS_RTC_KRTCR		0x3035 36/* Control */37#define CDNS_RTC_CTLR_TIME	BIT(0)38#define CDNS_RTC_CTLR_CAL	BIT(1)39#define CDNS_RTC_CTLR_TIME_CAL	(CDNS_RTC_CTLR_TIME | CDNS_RTC_CTLR_CAL)40 41/* Status */42#define CDNS_RTC_STSR_VT	BIT(0)43#define CDNS_RTC_STSR_VC	BIT(1)44#define CDNS_RTC_STSR_VTA	BIT(2)45#define CDNS_RTC_STSR_VCA	BIT(3)46#define CDNS_RTC_STSR_VT_VC	(CDNS_RTC_STSR_VT | CDNS_RTC_STSR_VC)47#define CDNS_RTC_STSR_VTA_VCA	(CDNS_RTC_STSR_VTA | CDNS_RTC_STSR_VCA)48 49/* Keep RTC */50#define CDNS_RTC_KRTCR_KRTC	BIT(0)51 52/* Alarm, Event, Interrupt */53#define CDNS_RTC_AEI_HOS	BIT(0)54#define CDNS_RTC_AEI_SEC	BIT(1)55#define CDNS_RTC_AEI_MIN	BIT(2)56#define CDNS_RTC_AEI_HOUR	BIT(3)57#define CDNS_RTC_AEI_DATE	BIT(4)58#define CDNS_RTC_AEI_MNTH	BIT(5)59#define CDNS_RTC_AEI_ALRM	BIT(6)60 61/* Time */62#define CDNS_RTC_TIME_H		GENMASK(7, 0)63#define CDNS_RTC_TIME_S		GENMASK(14, 8)64#define CDNS_RTC_TIME_M		GENMASK(22, 16)65#define CDNS_RTC_TIME_HR	GENMASK(29, 24)66#define CDNS_RTC_TIME_PM	BIT(30)67#define CDNS_RTC_TIME_CH	BIT(31)68 69/* Calendar */70#define CDNS_RTC_CAL_DAY	GENMASK(2, 0)71#define CDNS_RTC_CAL_M		GENMASK(7, 3)72#define CDNS_RTC_CAL_D		GENMASK(13, 8)73#define CDNS_RTC_CAL_Y		GENMASK(23, 16)74#define CDNS_RTC_CAL_C		GENMASK(29, 24)75#define CDNS_RTC_CAL_CH		BIT(31)76 77#define CDNS_RTC_MAX_REGS_TRIES	378 79struct cdns_rtc {80	struct rtc_device *rtc_dev;81	struct clk *pclk;82	struct clk *ref_clk;83	void __iomem *regs;84	int irq;85};86 87static void cdns_rtc_set_enabled(struct cdns_rtc *crtc, bool enabled)88{89	u32 reg = enabled ? 0x0 : CDNS_RTC_CTLR_TIME_CAL;90 91	writel(reg, crtc->regs + CDNS_RTC_CTLR);92}93 94static bool cdns_rtc_get_enabled(struct cdns_rtc *crtc)95{96	return !(readl(crtc->regs + CDNS_RTC_CTLR) & CDNS_RTC_CTLR_TIME_CAL);97}98 99static irqreturn_t cdns_rtc_irq_handler(int irq, void *id)100{101	struct device *dev = id;102	struct cdns_rtc *crtc = dev_get_drvdata(dev);103 104	/* Reading the register clears it */105	if (!(readl(crtc->regs + CDNS_RTC_EFLR) & CDNS_RTC_AEI_ALRM))106		return IRQ_NONE;107 108	rtc_update_irq(crtc->rtc_dev, 1, RTC_IRQF | RTC_AF);109	return IRQ_HANDLED;110}111 112static u32 cdns_rtc_time2reg(struct rtc_time *tm)113{114	return FIELD_PREP(CDNS_RTC_TIME_S,  bin2bcd(tm->tm_sec))115	     | FIELD_PREP(CDNS_RTC_TIME_M,  bin2bcd(tm->tm_min))116	     | FIELD_PREP(CDNS_RTC_TIME_HR, bin2bcd(tm->tm_hour));117}118 119static void cdns_rtc_reg2time(u32 reg, struct rtc_time *tm)120{121	tm->tm_sec  = bcd2bin(FIELD_GET(CDNS_RTC_TIME_S, reg));122	tm->tm_min  = bcd2bin(FIELD_GET(CDNS_RTC_TIME_M, reg));123	tm->tm_hour = bcd2bin(FIELD_GET(CDNS_RTC_TIME_HR, reg));124}125 126static int cdns_rtc_read_time(struct device *dev, struct rtc_time *tm)127{128	struct cdns_rtc *crtc = dev_get_drvdata(dev);129	u32 reg;130 131	/* If the RTC is disabled, assume the values are invalid */132	if (!cdns_rtc_get_enabled(crtc))133		return -EINVAL;134 135	cdns_rtc_set_enabled(crtc, false);136 137	reg = readl(crtc->regs + CDNS_RTC_TIMR);138	cdns_rtc_reg2time(reg, tm);139 140	reg = readl(crtc->regs + CDNS_RTC_CALR);141	tm->tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));142	tm->tm_mon  = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;143	tm->tm_year = bcd2bin(FIELD_GET(CDNS_RTC_CAL_Y, reg))144		    + bcd2bin(FIELD_GET(CDNS_RTC_CAL_C, reg)) * 100 - 1900;145	tm->tm_wday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_DAY, reg)) - 1;146 147	cdns_rtc_set_enabled(crtc, true);148	return 0;149}150 151static int cdns_rtc_set_time(struct device *dev, struct rtc_time *tm)152{153	struct cdns_rtc *crtc = dev_get_drvdata(dev);154	u32 timr, calr, stsr;155	int ret = -EIO;156	int year = tm->tm_year + 1900;157	int tries;158 159	cdns_rtc_set_enabled(crtc, false);160 161	timr = cdns_rtc_time2reg(tm);162 163	calr = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(tm->tm_mday))164	     | FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(tm->tm_mon + 1))165	     | FIELD_PREP(CDNS_RTC_CAL_Y, bin2bcd(year % 100))166	     | FIELD_PREP(CDNS_RTC_CAL_C, bin2bcd(year / 100))167	     | FIELD_PREP(CDNS_RTC_CAL_DAY, tm->tm_wday + 1);168 169	/* Update registers, check valid flags */170	for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {171		writel(timr, crtc->regs + CDNS_RTC_TIMR);172		writel(calr, crtc->regs + CDNS_RTC_CALR);173		stsr = readl(crtc->regs + CDNS_RTC_STSR);174 175		if ((stsr & CDNS_RTC_STSR_VT_VC) == CDNS_RTC_STSR_VT_VC) {176			ret = 0;177			break;178		}179	}180 181	cdns_rtc_set_enabled(crtc, true);182	return ret;183}184 185static int cdns_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)186{187	struct cdns_rtc *crtc = dev_get_drvdata(dev);188 189	if (enabled) {190		writel((CDNS_RTC_AEI_SEC | CDNS_RTC_AEI_MIN | CDNS_RTC_AEI_HOUR191			| CDNS_RTC_AEI_DATE | CDNS_RTC_AEI_MNTH),192		       crtc->regs + CDNS_RTC_AENR);193		writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IENR);194	} else {195		writel(0, crtc->regs + CDNS_RTC_AENR);196		writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IDISR);197	}198 199	return 0;200}201 202static int cdns_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)203{204	struct cdns_rtc *crtc = dev_get_drvdata(dev);205	u32 reg;206 207	reg = readl(crtc->regs + CDNS_RTC_TIMAR);208	cdns_rtc_reg2time(reg, &alarm->time);209 210	reg = readl(crtc->regs + CDNS_RTC_CALAR);211	alarm->time.tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));212	alarm->time.tm_mon  = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;213 214	return 0;215}216 217static int cdns_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)218{219	struct cdns_rtc *crtc = dev_get_drvdata(dev);220	int ret = -EIO;221	int tries;222	u32 timar, calar, stsr;223 224	cdns_rtc_alarm_irq_enable(dev, 0);225 226	timar = cdns_rtc_time2reg(&alarm->time);227	calar = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(alarm->time.tm_mday))228	      | FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(alarm->time.tm_mon + 1));229 230	/* Update registers, check valid alarm flags */231	for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {232		writel(timar, crtc->regs + CDNS_RTC_TIMAR);233		writel(calar, crtc->regs + CDNS_RTC_CALAR);234		stsr = readl(crtc->regs + CDNS_RTC_STSR);235 236		if ((stsr & CDNS_RTC_STSR_VTA_VCA) == CDNS_RTC_STSR_VTA_VCA) {237			ret = 0;238			break;239		}240	}241 242	if (!ret)243		cdns_rtc_alarm_irq_enable(dev, alarm->enabled);244	return ret;245}246 247static const struct rtc_class_ops cdns_rtc_ops = {248	.read_time	= cdns_rtc_read_time,249	.set_time	= cdns_rtc_set_time,250	.read_alarm	= cdns_rtc_read_alarm,251	.set_alarm	= cdns_rtc_set_alarm,252	.alarm_irq_enable = cdns_rtc_alarm_irq_enable,253};254 255static int cdns_rtc_probe(struct platform_device *pdev)256{257	struct cdns_rtc *crtc;258	int ret;259	unsigned long ref_clk_freq;260 261	crtc = devm_kzalloc(&pdev->dev, sizeof(*crtc), GFP_KERNEL);262	if (!crtc)263		return -ENOMEM;264 265	crtc->regs = devm_platform_ioremap_resource(pdev, 0);266	if (IS_ERR(crtc->regs))267		return PTR_ERR(crtc->regs);268 269	crtc->irq = platform_get_irq(pdev, 0);270	if (crtc->irq < 0)271		return -EINVAL;272 273	crtc->pclk = devm_clk_get(&pdev->dev, "pclk");274	if (IS_ERR(crtc->pclk)) {275		ret = PTR_ERR(crtc->pclk);276		dev_err(&pdev->dev,277			"Failed to retrieve the peripheral clock, %d\n", ret);278		return ret;279	}280 281	crtc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");282	if (IS_ERR(crtc->ref_clk)) {283		ret = PTR_ERR(crtc->ref_clk);284		dev_err(&pdev->dev,285			"Failed to retrieve the reference clock, %d\n", ret);286		return ret;287	}288 289	crtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);290	if (IS_ERR(crtc->rtc_dev))291		return PTR_ERR(crtc->rtc_dev);292 293	platform_set_drvdata(pdev, crtc);294 295	ret = clk_prepare_enable(crtc->pclk);296	if (ret) {297		dev_err(&pdev->dev,298			"Failed to enable the peripheral clock, %d\n", ret);299		return ret;300	}301 302	ret = clk_prepare_enable(crtc->ref_clk);303	if (ret) {304		dev_err(&pdev->dev,305			"Failed to enable the reference clock, %d\n", ret);306		goto err_disable_pclk;307	}308 309	ref_clk_freq = clk_get_rate(crtc->ref_clk);310	if ((ref_clk_freq != 1) && (ref_clk_freq != 100)) {311		dev_err(&pdev->dev,312			"Invalid reference clock frequency %lu Hz.\n",313			ref_clk_freq);314		ret = -EINVAL;315		goto err_disable_ref_clk;316	}317 318	ret = devm_request_irq(&pdev->dev, crtc->irq,319			       cdns_rtc_irq_handler, 0,320			       dev_name(&pdev->dev), &pdev->dev);321	if (ret) {322		dev_err(&pdev->dev,323			"Failed to request interrupt for the device, %d\n",324			ret);325		goto err_disable_ref_clk;326	}327 328	/* The RTC supports 01.01.1900 - 31.12.2999 */329	crtc->rtc_dev->range_min = mktime64(1900,  1,  1,  0,  0,  0);330	crtc->rtc_dev->range_max = mktime64(2999, 12, 31, 23, 59, 59);331 332	crtc->rtc_dev->ops = &cdns_rtc_ops;333	device_init_wakeup(&pdev->dev, true);334 335	/* Always use 24-hour mode and keep the RTC values */336	writel(0, crtc->regs + CDNS_RTC_HMR);337	writel(CDNS_RTC_KRTCR_KRTC, crtc->regs + CDNS_RTC_KRTCR);338 339	ret = devm_rtc_register_device(crtc->rtc_dev);340	if (ret)341		goto err_disable_wakeup;342 343	return 0;344 345err_disable_wakeup:346	device_init_wakeup(&pdev->dev, false);347 348err_disable_ref_clk:349	clk_disable_unprepare(crtc->ref_clk);350 351err_disable_pclk:352	clk_disable_unprepare(crtc->pclk);353 354	return ret;355}356 357static void cdns_rtc_remove(struct platform_device *pdev)358{359	struct cdns_rtc *crtc = platform_get_drvdata(pdev);360 361	cdns_rtc_alarm_irq_enable(&pdev->dev, 0);362	device_init_wakeup(&pdev->dev, 0);363 364	clk_disable_unprepare(crtc->pclk);365	clk_disable_unprepare(crtc->ref_clk);366}367 368#ifdef CONFIG_PM_SLEEP369static int cdns_rtc_suspend(struct device *dev)370{371	struct cdns_rtc *crtc = dev_get_drvdata(dev);372 373	if (device_may_wakeup(dev))374		enable_irq_wake(crtc->irq);375 376	return 0;377}378 379static int cdns_rtc_resume(struct device *dev)380{381	struct cdns_rtc *crtc = dev_get_drvdata(dev);382 383	if (device_may_wakeup(dev))384		disable_irq_wake(crtc->irq);385 386	return 0;387}388#endif389 390static SIMPLE_DEV_PM_OPS(cdns_rtc_pm_ops, cdns_rtc_suspend, cdns_rtc_resume);391 392static const struct of_device_id cdns_rtc_of_match[] = {393	{ .compatible = "cdns,rtc-r109v3" },394	{ },395};396MODULE_DEVICE_TABLE(of, cdns_rtc_of_match);397 398static struct platform_driver cdns_rtc_driver = {399	.driver = {400		.name = "cdns-rtc",401		.of_match_table = cdns_rtc_of_match,402		.pm = &cdns_rtc_pm_ops,403	},404	.probe = cdns_rtc_probe,405	.remove_new = cdns_rtc_remove,406};407module_platform_driver(cdns_rtc_driver);408 409MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");410MODULE_DESCRIPTION("Cadence RTC driver");411MODULE_LICENSE("GPL v2");412MODULE_ALIAS("platform:cdns-rtc");413