1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Faraday Technology FTRTC010 driver
5 * Copyright (C) 2009 Janos Laube <janos.dev@gmail.com>
7 * Original code for older kernel 2.6.15 are from Stormlinksemi
8 * first update from Janos Laube for > 2.6.29 kernels
10 * checkpatch fixes and usage of rtc-lib code
11 * Hans Ulli Kroll <ulli.kroll@googlemail.com>
14 #include <linux/rtc.h>
16 #include <linux/slab.h>
17 #include <linux/platform_device.h>
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/mod_devicetable.h>
21 #include <linux/clk.h>
23 #define DRV_NAME "rtc-ftrtc010"
25 MODULE_AUTHOR("Hans Ulli Kroll <ulli.kroll@googlemail.com>");
26 MODULE_DESCRIPTION("RTC driver for Gemini SoC");
27 MODULE_LICENSE("GPL");
28 MODULE_ALIAS("platform:" DRV_NAME
);
31 struct rtc_device
*rtc_dev
;
32 void __iomem
*rtc_base
;
38 enum ftrtc010_rtc_offsets
{
39 FTRTC010_RTC_SECOND
= 0x00,
40 FTRTC010_RTC_MINUTE
= 0x04,
41 FTRTC010_RTC_HOUR
= 0x08,
42 FTRTC010_RTC_DAYS
= 0x0C,
43 FTRTC010_RTC_ALARM_SECOND
= 0x10,
44 FTRTC010_RTC_ALARM_MINUTE
= 0x14,
45 FTRTC010_RTC_ALARM_HOUR
= 0x18,
46 FTRTC010_RTC_RECORD
= 0x1C,
47 FTRTC010_RTC_CR
= 0x20,
50 static irqreturn_t
ftrtc010_rtc_interrupt(int irq
, void *dev
)
56 * Looks like the RTC in the Gemini SoC is (totaly) broken
57 * We can't read/write directly the time from RTC registers.
58 * We must do some "offset" calculation to get the real time
60 * This FIX works pretty fine and Stormlinksemi aka Cortina-Networks does
61 * the same thing, without the rtc-lib.c calls.
64 static int ftrtc010_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
66 struct ftrtc010_rtc
*rtc
= dev_get_drvdata(dev
);
68 u32 days
, hour
, min
, sec
, offset
;
71 sec
= readl(rtc
->rtc_base
+ FTRTC010_RTC_SECOND
);
72 min
= readl(rtc
->rtc_base
+ FTRTC010_RTC_MINUTE
);
73 hour
= readl(rtc
->rtc_base
+ FTRTC010_RTC_HOUR
);
74 days
= readl(rtc
->rtc_base
+ FTRTC010_RTC_DAYS
);
75 offset
= readl(rtc
->rtc_base
+ FTRTC010_RTC_RECORD
);
77 time
= offset
+ days
* 86400 + hour
* 3600 + min
* 60 + sec
;
79 rtc_time64_to_tm(time
, tm
);
84 static int ftrtc010_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
86 struct ftrtc010_rtc
*rtc
= dev_get_drvdata(dev
);
87 u32 sec
, min
, hour
, day
, offset
;
90 time
= rtc_tm_to_time64(tm
);
92 sec
= readl(rtc
->rtc_base
+ FTRTC010_RTC_SECOND
);
93 min
= readl(rtc
->rtc_base
+ FTRTC010_RTC_MINUTE
);
94 hour
= readl(rtc
->rtc_base
+ FTRTC010_RTC_HOUR
);
95 day
= readl(rtc
->rtc_base
+ FTRTC010_RTC_DAYS
);
97 offset
= time
- (day
* 86400 + hour
* 3600 + min
* 60 + sec
);
99 writel(offset
, rtc
->rtc_base
+ FTRTC010_RTC_RECORD
);
100 writel(0x01, rtc
->rtc_base
+ FTRTC010_RTC_CR
);
105 static const struct rtc_class_ops ftrtc010_rtc_ops
= {
106 .read_time
= ftrtc010_rtc_read_time
,
107 .set_time
= ftrtc010_rtc_set_time
,
110 static int ftrtc010_rtc_probe(struct platform_device
*pdev
)
112 u32 days
, hour
, min
, sec
;
113 struct ftrtc010_rtc
*rtc
;
114 struct device
*dev
= &pdev
->dev
;
115 struct resource
*res
;
118 rtc
= devm_kzalloc(&pdev
->dev
, sizeof(*rtc
), GFP_KERNEL
);
121 platform_set_drvdata(pdev
, rtc
);
123 rtc
->pclk
= devm_clk_get(dev
, "PCLK");
124 if (IS_ERR(rtc
->pclk
)) {
125 dev_err(dev
, "could not get PCLK\n");
127 ret
= clk_prepare_enable(rtc
->pclk
);
129 dev_err(dev
, "failed to enable PCLK\n");
133 rtc
->extclk
= devm_clk_get(dev
, "EXTCLK");
134 if (IS_ERR(rtc
->extclk
)) {
135 dev_err(dev
, "could not get EXTCLK\n");
137 ret
= clk_prepare_enable(rtc
->extclk
);
139 dev_err(dev
, "failed to enable EXTCLK\n");
144 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
148 rtc
->rtc_irq
= res
->start
;
150 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
154 rtc
->rtc_base
= devm_ioremap(dev
, res
->start
,
159 rtc
->rtc_dev
= devm_rtc_allocate_device(dev
);
160 if (IS_ERR(rtc
->rtc_dev
))
161 return PTR_ERR(rtc
->rtc_dev
);
163 rtc
->rtc_dev
->ops
= &ftrtc010_rtc_ops
;
165 sec
= readl(rtc
->rtc_base
+ FTRTC010_RTC_SECOND
);
166 min
= readl(rtc
->rtc_base
+ FTRTC010_RTC_MINUTE
);
167 hour
= readl(rtc
->rtc_base
+ FTRTC010_RTC_HOUR
);
168 days
= readl(rtc
->rtc_base
+ FTRTC010_RTC_DAYS
);
170 rtc
->rtc_dev
->range_min
= (u64
)days
* 86400 + hour
* 3600 +
172 rtc
->rtc_dev
->range_max
= U32_MAX
+ rtc
->rtc_dev
->range_min
;
174 ret
= devm_request_irq(dev
, rtc
->rtc_irq
, ftrtc010_rtc_interrupt
,
175 IRQF_SHARED
, pdev
->name
, dev
);
179 return devm_rtc_register_device(rtc
->rtc_dev
);
182 static int ftrtc010_rtc_remove(struct platform_device
*pdev
)
184 struct ftrtc010_rtc
*rtc
= platform_get_drvdata(pdev
);
186 if (!IS_ERR(rtc
->extclk
))
187 clk_disable_unprepare(rtc
->extclk
);
188 if (!IS_ERR(rtc
->pclk
))
189 clk_disable_unprepare(rtc
->pclk
);
194 static const struct of_device_id ftrtc010_rtc_dt_match
[] = {
195 { .compatible
= "cortina,gemini-rtc" },
196 { .compatible
= "faraday,ftrtc010" },
199 MODULE_DEVICE_TABLE(of
, ftrtc010_rtc_dt_match
);
201 static struct platform_driver ftrtc010_rtc_driver
= {
204 .of_match_table
= ftrtc010_rtc_dt_match
,
206 .probe
= ftrtc010_rtc_probe
,
207 .remove
= ftrtc010_rtc_remove
,
210 module_platform_driver_probe(ftrtc010_rtc_driver
, ftrtc010_rtc_probe
);