xref: /OK3568_Linux_fs/kernel/drivers/rtc/rtc-xgene.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * APM X-Gene SoC Real Time Clock Driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2014, Applied Micro Circuits Corporation
6*4882a593Smuzhiyun  * Author: Rameshwar Prasad Sahu <rsahu@apm.com>
7*4882a593Smuzhiyun  *         Loc Ho <lho@apm.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/clk.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/of.h>
16*4882a593Smuzhiyun #include <linux/platform_device.h>
17*4882a593Smuzhiyun #include <linux/rtc.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* RTC CSR Registers */
21*4882a593Smuzhiyun #define RTC_CCVR		0x00
22*4882a593Smuzhiyun #define RTC_CMR			0x04
23*4882a593Smuzhiyun #define RTC_CLR			0x08
24*4882a593Smuzhiyun #define RTC_CCR			0x0C
25*4882a593Smuzhiyun #define  RTC_CCR_IE		BIT(0)
26*4882a593Smuzhiyun #define  RTC_CCR_MASK		BIT(1)
27*4882a593Smuzhiyun #define  RTC_CCR_EN		BIT(2)
28*4882a593Smuzhiyun #define  RTC_CCR_WEN		BIT(3)
29*4882a593Smuzhiyun #define RTC_STAT		0x10
30*4882a593Smuzhiyun #define  RTC_STAT_BIT		BIT(0)
31*4882a593Smuzhiyun #define RTC_RSTAT		0x14
32*4882a593Smuzhiyun #define RTC_EOI			0x18
33*4882a593Smuzhiyun #define RTC_VER			0x1C
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun struct xgene_rtc_dev {
36*4882a593Smuzhiyun 	struct rtc_device *rtc;
37*4882a593Smuzhiyun 	void __iomem *csr_base;
38*4882a593Smuzhiyun 	struct clk *clk;
39*4882a593Smuzhiyun 	unsigned int irq_wake;
40*4882a593Smuzhiyun 	unsigned int irq_enabled;
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun 
xgene_rtc_read_time(struct device * dev,struct rtc_time * tm)43*4882a593Smuzhiyun static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	rtc_time64_to_tm(readl(pdata->csr_base + RTC_CCVR), tm);
48*4882a593Smuzhiyun 	return 0;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
xgene_rtc_set_time(struct device * dev,struct rtc_time * tm)51*4882a593Smuzhiyun static int xgene_rtc_set_time(struct device *dev, struct rtc_time *tm)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/*
56*4882a593Smuzhiyun 	 * NOTE: After the following write, the RTC_CCVR is only reflected
57*4882a593Smuzhiyun 	 *       after the update cycle of 1 seconds.
58*4882a593Smuzhiyun 	 */
59*4882a593Smuzhiyun 	writel((u32)rtc_tm_to_time64(tm), pdata->csr_base + RTC_CLR);
60*4882a593Smuzhiyun 	readl(pdata->csr_base + RTC_CLR); /* Force a barrier */
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	return 0;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
xgene_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alrm)65*4882a593Smuzhiyun static int xgene_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	/* If possible, CMR should be read here */
70*4882a593Smuzhiyun 	rtc_time64_to_tm(0, &alrm->time);
71*4882a593Smuzhiyun 	alrm->enabled = readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
xgene_rtc_alarm_irq_enable(struct device * dev,u32 enabled)76*4882a593Smuzhiyun static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
79*4882a593Smuzhiyun 	u32 ccr;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	ccr = readl(pdata->csr_base + RTC_CCR);
82*4882a593Smuzhiyun 	if (enabled) {
83*4882a593Smuzhiyun 		ccr &= ~RTC_CCR_MASK;
84*4882a593Smuzhiyun 		ccr |= RTC_CCR_IE;
85*4882a593Smuzhiyun 	} else {
86*4882a593Smuzhiyun 		ccr &= ~RTC_CCR_IE;
87*4882a593Smuzhiyun 		ccr |= RTC_CCR_MASK;
88*4882a593Smuzhiyun 	}
89*4882a593Smuzhiyun 	writel(ccr, pdata->csr_base + RTC_CCR);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	return 0;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
xgene_rtc_alarm_irq_enabled(struct device * dev)94*4882a593Smuzhiyun static int xgene_rtc_alarm_irq_enabled(struct device *dev)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	return readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE ? 1 : 0;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
xgene_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alrm)101*4882a593Smuzhiyun static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	writel((u32)rtc_tm_to_time64(&alrm->time), pdata->csr_base + RTC_CMR);
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	xgene_rtc_alarm_irq_enable(dev, alrm->enabled);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun static const struct rtc_class_ops xgene_rtc_ops = {
113*4882a593Smuzhiyun 	.read_time	= xgene_rtc_read_time,
114*4882a593Smuzhiyun 	.set_time	= xgene_rtc_set_time,
115*4882a593Smuzhiyun 	.read_alarm	= xgene_rtc_read_alarm,
116*4882a593Smuzhiyun 	.set_alarm	= xgene_rtc_set_alarm,
117*4882a593Smuzhiyun 	.alarm_irq_enable = xgene_rtc_alarm_irq_enable,
118*4882a593Smuzhiyun };
119*4882a593Smuzhiyun 
xgene_rtc_interrupt(int irq,void * id)120*4882a593Smuzhiyun static irqreturn_t xgene_rtc_interrupt(int irq, void *id)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = id;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	/* Check if interrupt asserted */
125*4882a593Smuzhiyun 	if (!(readl(pdata->csr_base + RTC_STAT) & RTC_STAT_BIT))
126*4882a593Smuzhiyun 		return IRQ_NONE;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/* Clear interrupt */
129*4882a593Smuzhiyun 	readl(pdata->csr_base + RTC_EOI);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	return IRQ_HANDLED;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
xgene_rtc_probe(struct platform_device * pdev)136*4882a593Smuzhiyun static int xgene_rtc_probe(struct platform_device *pdev)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata;
139*4882a593Smuzhiyun 	int ret;
140*4882a593Smuzhiyun 	int irq;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
143*4882a593Smuzhiyun 	if (!pdata)
144*4882a593Smuzhiyun 		return -ENOMEM;
145*4882a593Smuzhiyun 	platform_set_drvdata(pdev, pdata);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	pdata->csr_base = devm_platform_ioremap_resource(pdev, 0);
148*4882a593Smuzhiyun 	if (IS_ERR(pdata->csr_base))
149*4882a593Smuzhiyun 		return PTR_ERR(pdata->csr_base);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
152*4882a593Smuzhiyun 	if (IS_ERR(pdata->rtc))
153*4882a593Smuzhiyun 		return PTR_ERR(pdata->rtc);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
156*4882a593Smuzhiyun 	if (irq < 0)
157*4882a593Smuzhiyun 		return irq;
158*4882a593Smuzhiyun 	ret = devm_request_irq(&pdev->dev, irq, xgene_rtc_interrupt, 0,
159*4882a593Smuzhiyun 			       dev_name(&pdev->dev), pdata);
160*4882a593Smuzhiyun 	if (ret) {
161*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Could not request IRQ\n");
162*4882a593Smuzhiyun 		return ret;
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	pdata->clk = devm_clk_get(&pdev->dev, NULL);
166*4882a593Smuzhiyun 	if (IS_ERR(pdata->clk)) {
167*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Couldn't get the clock for RTC\n");
168*4882a593Smuzhiyun 		return -ENODEV;
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun 	ret = clk_prepare_enable(pdata->clk);
171*4882a593Smuzhiyun 	if (ret)
172*4882a593Smuzhiyun 		return ret;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	/* Turn on the clock and the crystal */
175*4882a593Smuzhiyun 	writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	ret = device_init_wakeup(&pdev->dev, 1);
178*4882a593Smuzhiyun 	if (ret) {
179*4882a593Smuzhiyun 		clk_disable_unprepare(pdata->clk);
180*4882a593Smuzhiyun 		return ret;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	/* HW does not support update faster than 1 seconds */
184*4882a593Smuzhiyun 	pdata->rtc->uie_unsupported = 1;
185*4882a593Smuzhiyun 	pdata->rtc->ops = &xgene_rtc_ops;
186*4882a593Smuzhiyun 	pdata->rtc->range_max = U32_MAX;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	ret = rtc_register_device(pdata->rtc);
189*4882a593Smuzhiyun 	if (ret) {
190*4882a593Smuzhiyun 		clk_disable_unprepare(pdata->clk);
191*4882a593Smuzhiyun 		return ret;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	return 0;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
xgene_rtc_remove(struct platform_device * pdev)197*4882a593Smuzhiyun static int xgene_rtc_remove(struct platform_device *pdev)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	xgene_rtc_alarm_irq_enable(&pdev->dev, 0);
202*4882a593Smuzhiyun 	device_init_wakeup(&pdev->dev, 0);
203*4882a593Smuzhiyun 	clk_disable_unprepare(pdata->clk);
204*4882a593Smuzhiyun 	return 0;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
xgene_rtc_suspend(struct device * dev)207*4882a593Smuzhiyun static int __maybe_unused xgene_rtc_suspend(struct device *dev)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	struct platform_device *pdev = to_platform_device(dev);
210*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
211*4882a593Smuzhiyun 	int irq;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	/*
216*4882a593Smuzhiyun 	 * If this RTC alarm will be used for waking the system up,
217*4882a593Smuzhiyun 	 * don't disable it of course. Else we just disable the alarm
218*4882a593Smuzhiyun 	 * and await suspension.
219*4882a593Smuzhiyun 	 */
220*4882a593Smuzhiyun 	if (device_may_wakeup(&pdev->dev)) {
221*4882a593Smuzhiyun 		if (!enable_irq_wake(irq))
222*4882a593Smuzhiyun 			pdata->irq_wake = 1;
223*4882a593Smuzhiyun 	} else {
224*4882a593Smuzhiyun 		pdata->irq_enabled = xgene_rtc_alarm_irq_enabled(dev);
225*4882a593Smuzhiyun 		xgene_rtc_alarm_irq_enable(dev, 0);
226*4882a593Smuzhiyun 		clk_disable_unprepare(pdata->clk);
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 	return 0;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
xgene_rtc_resume(struct device * dev)231*4882a593Smuzhiyun static int __maybe_unused xgene_rtc_resume(struct device *dev)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct platform_device *pdev = to_platform_device(dev);
234*4882a593Smuzhiyun 	struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
235*4882a593Smuzhiyun 	int irq;
236*4882a593Smuzhiyun 	int rc;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	if (device_may_wakeup(&pdev->dev)) {
241*4882a593Smuzhiyun 		if (pdata->irq_wake) {
242*4882a593Smuzhiyun 			disable_irq_wake(irq);
243*4882a593Smuzhiyun 			pdata->irq_wake = 0;
244*4882a593Smuzhiyun 		}
245*4882a593Smuzhiyun 	} else {
246*4882a593Smuzhiyun 		rc = clk_prepare_enable(pdata->clk);
247*4882a593Smuzhiyun 		if (rc) {
248*4882a593Smuzhiyun 			dev_err(dev, "Unable to enable clock error %d\n", rc);
249*4882a593Smuzhiyun 			return rc;
250*4882a593Smuzhiyun 		}
251*4882a593Smuzhiyun 		xgene_rtc_alarm_irq_enable(dev, pdata->irq_enabled);
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	return 0;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops, xgene_rtc_suspend, xgene_rtc_resume);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun #ifdef CONFIG_OF
260*4882a593Smuzhiyun static const struct of_device_id xgene_rtc_of_match[] = {
261*4882a593Smuzhiyun 	{.compatible = "apm,xgene-rtc" },
262*4882a593Smuzhiyun 	{ }
263*4882a593Smuzhiyun };
264*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, xgene_rtc_of_match);
265*4882a593Smuzhiyun #endif
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun static struct platform_driver xgene_rtc_driver = {
268*4882a593Smuzhiyun 	.probe		= xgene_rtc_probe,
269*4882a593Smuzhiyun 	.remove		= xgene_rtc_remove,
270*4882a593Smuzhiyun 	.driver		= {
271*4882a593Smuzhiyun 		.name	= "xgene-rtc",
272*4882a593Smuzhiyun 		.pm = &xgene_rtc_pm_ops,
273*4882a593Smuzhiyun 		.of_match_table	= of_match_ptr(xgene_rtc_of_match),
274*4882a593Smuzhiyun 	},
275*4882a593Smuzhiyun };
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun module_platform_driver(xgene_rtc_driver);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun MODULE_DESCRIPTION("APM X-Gene SoC RTC driver");
280*4882a593Smuzhiyun MODULE_AUTHOR("Rameshwar Sahu <rsahu@apm.com>");
281*4882a593Smuzhiyun MODULE_LICENSE("GPL");
282