aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTianping Fang <tianping.fang@mediatek.com>2015-05-06 03:23:41 -0400
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2015-06-24 19:13:35 -0400
commitfc2979118f3f5193475cb53d5df7bdaa7e358a42 (patch)
treeb291b976349a19fc9f642bd67821739ef270488d
parenta5d7ea0912cc35efb61bccb1f07432f25fce6281 (diff)
rtc: mediatek: Add MT6397 RTC driver
Add Mediatek MT6397 RTC driver Signed-off-by: Tianping Fang <tianping.fang@mediatek.com> Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-mt6397.c394
3 files changed, 405 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index b957b4f67f0f..20a1f35dc0d5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1530,6 +1530,16 @@ config RTC_DRV_MOXART
1530 This driver can also be built as a module. If so, the module 1530 This driver can also be built as a module. If so, the module
1531 will be called rtc-moxart 1531 will be called rtc-moxart
1532 1532
1533config RTC_DRV_MT6397
1534 tristate "Mediatek Real Time Clock driver"
1535 depends on MFD_MT6397 || COMPILE_TEST
1536 help
1537 This selects the Mediatek(R) RTC driver. RTC is part of Mediatek
1538 MT6397 PMIC. You should enable MT6397 PMIC MFD before select
1539 Mediatek(R) RTC driver.
1540
1541 If you want to use Mediatek(R) RTC interface, select Y or M here.
1542
1533config RTC_DRV_XGENE 1543config RTC_DRV_XGENE
1534 tristate "APM X-Gene RTC" 1544 tristate "APM X-Gene RTC"
1535 depends on HAS_IOMEM 1545 depends on HAS_IOMEM
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 2b82e2b0311b..371d97795fb5 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -155,3 +155,4 @@ obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
155obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o 155obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o
156obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o 156obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
157obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o 157obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
158obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o
diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
new file mode 100644
index 000000000000..8bed852e4961
--- /dev/null
+++ b/drivers/rtc/rtc-mt6397.c
@@ -0,0 +1,394 @@
1/*
2* Copyright (c) 2014-2015 MediaTek Inc.
3* Author: Tianping.Fang <tianping.fang@mediatek.com>
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License version 2 as
7* published by the Free Software Foundation.
8*
9* This program is distributed in the hope that it will be useful,
10* but WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12* GNU General Public License for more details.
13*/
14
15#include <linux/delay.h>
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/regmap.h>
19#include <linux/rtc.h>
20#include <linux/irqdomain.h>
21#include <linux/platform_device.h>
22#include <linux/of_address.h>
23#include <linux/of_irq.h>
24#include <linux/io.h>
25#include <linux/mfd/mt6397/core.h>
26
27#define RTC_BBPU 0x0000
28#define RTC_BBPU_CBUSY BIT(6)
29
30#define RTC_WRTGR 0x003c
31
32#define RTC_IRQ_STA 0x0002
33#define RTC_IRQ_STA_AL BIT(0)
34#define RTC_IRQ_STA_LP BIT(3)
35
36#define RTC_IRQ_EN 0x0004
37#define RTC_IRQ_EN_AL BIT(0)
38#define RTC_IRQ_EN_ONESHOT BIT(2)
39#define RTC_IRQ_EN_LP BIT(3)
40#define RTC_IRQ_EN_ONESHOT_AL (RTC_IRQ_EN_ONESHOT | RTC_IRQ_EN_AL)
41
42#define RTC_AL_MASK 0x0008
43#define RTC_AL_MASK_DOW BIT(4)
44
45#define RTC_TC_SEC 0x000a
46/* Min, Hour, Dom... register offset to RTC_TC_SEC */
47#define RTC_OFFSET_SEC 0
48#define RTC_OFFSET_MIN 1
49#define RTC_OFFSET_HOUR 2
50#define RTC_OFFSET_DOM 3
51#define RTC_OFFSET_DOW 4
52#define RTC_OFFSET_MTH 5
53#define RTC_OFFSET_YEAR 6
54#define RTC_OFFSET_COUNT 7
55
56#define RTC_AL_SEC 0x0018
57
58#define RTC_PDN2 0x002e
59#define RTC_PDN2_PWRON_ALARM BIT(4)
60
61#define RTC_MIN_YEAR 1968
62#define RTC_BASE_YEAR 1900
63#define RTC_NUM_YEARS 128
64#define RTC_MIN_YEAR_OFFSET (RTC_MIN_YEAR - RTC_BASE_YEAR)
65
66struct mt6397_rtc {
67 struct device *dev;
68 struct rtc_device *rtc_dev;
69 struct mutex lock;
70 struct regmap *regmap;
71 int irq;
72 u32 addr_base;
73};
74
75static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc)
76{
77 unsigned long timeout = jiffies + HZ;
78 int ret;
79 u32 data;
80
81 ret = regmap_write(rtc->regmap, rtc->addr_base + RTC_WRTGR, 1);
82 if (ret < 0)
83 return ret;
84
85 while (1) {
86 ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_BBPU,
87 &data);
88 if (ret < 0)
89 break;
90 if (!(data & RTC_BBPU_CBUSY))
91 break;
92 if (time_after(jiffies, timeout)) {
93 ret = -ETIMEDOUT;
94 break;
95 }
96 cpu_relax();
97 }
98
99 return ret;
100}
101
102static irqreturn_t mtk_rtc_irq_handler_thread(int irq, void *data)
103{
104 struct mt6397_rtc *rtc = data;
105 u32 irqsta, irqen;
106 int ret;
107
108 ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_IRQ_STA, &irqsta);
109 if ((ret >= 0) && (irqsta & RTC_IRQ_STA_AL)) {
110 rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
111 irqen = irqsta & ~RTC_IRQ_EN_AL;
112 mutex_lock(&rtc->lock);
113 if (regmap_write(rtc->regmap, rtc->addr_base + RTC_IRQ_EN,
114 irqen) < 0)
115 mtk_rtc_write_trigger(rtc);
116 mutex_unlock(&rtc->lock);
117
118 return IRQ_HANDLED;
119 }
120
121 return IRQ_NONE;
122}
123
124static int __mtk_rtc_read_time(struct mt6397_rtc *rtc,
125 struct rtc_time *tm, int *sec)
126{
127 int ret;
128 u16 data[RTC_OFFSET_COUNT];
129
130 mutex_lock(&rtc->lock);
131 ret = regmap_bulk_read(rtc->regmap, rtc->addr_base + RTC_TC_SEC,
132 data, RTC_OFFSET_COUNT);
133 if (ret < 0)
134 goto exit;
135
136 tm->tm_sec = data[RTC_OFFSET_SEC];
137 tm->tm_min = data[RTC_OFFSET_MIN];
138 tm->tm_hour = data[RTC_OFFSET_HOUR];
139 tm->tm_mday = data[RTC_OFFSET_DOM];
140 tm->tm_mon = data[RTC_OFFSET_MTH];
141 tm->tm_year = data[RTC_OFFSET_YEAR];
142
143 ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_TC_SEC, sec);
144exit:
145 mutex_unlock(&rtc->lock);
146 return ret;
147}
148
149static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
150{
151 time64_t time;
152 struct mt6397_rtc *rtc = dev_get_drvdata(dev);
153 int sec, ret;
154
155 do {
156 ret = __mtk_rtc_read_time(rtc, tm, &sec);
157 if (ret < 0)
158 goto exit;
159 } while (sec < tm->tm_sec);
160
161 /* HW register use 7 bits to store year data, minus
162 * RTC_MIN_YEAR_OFFSET before write year data to register, and plus
163 * RTC_MIN_YEAR_OFFSET back after read year from register
164 */
165 tm->tm_year += RTC_MIN_YEAR_OFFSET;
166
167 /* HW register start mon from one, but tm_mon start from zero. */
168 tm->tm_mon--;
169 time = rtc_tm_to_time64(tm);
170
171 /* rtc_tm_to_time64 covert Gregorian date to seconds since
172 * 01-01-1970 00:00:00, and this date is Thursday.
173 */
174 tm->tm_wday = (time / 86400 + 4) % 7;
175
176exit:
177 return ret;
178}
179
180static int mtk_rtc_set_time(struct device *dev, struct rtc_time *tm)
181{
182 struct mt6397_rtc *rtc = dev_get_drvdata(dev);
183 int ret;
184 u16 data[RTC_OFFSET_COUNT];
185
186 tm->tm_year -= RTC_MIN_YEAR_OFFSET;
187 tm->tm_mon++;
188
189 data[RTC_OFFSET_SEC] = tm->tm_sec;
190 data[RTC_OFFSET_MIN] = tm->tm_min;
191 data[RTC_OFFSET_HOUR] = tm->tm_hour;
192 data[RTC_OFFSET_DOM] = tm->tm_mday;
193 data[RTC_OFFSET_MTH] = tm->tm_mon;
194 data[RTC_OFFSET_YEAR] = tm->tm_year;
195
196 mutex_lock(&rtc->lock);
197 ret = regmap_bulk_write(rtc->regmap, rtc->addr_base + RTC_TC_SEC,
198 data, RTC_OFFSET_COUNT);
199 if (ret < 0)
200 goto exit;
201
202 /* Time register write to hardware after call trigger function */
203 ret = mtk_rtc_write_trigger(rtc);
204
205exit:
206 mutex_unlock(&rtc->lock);
207 return ret;
208}
209
210static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
211{
212 struct rtc_time *tm = &alm->time;
213 struct mt6397_rtc *rtc = dev_get_drvdata(dev);
214 u32 irqen, pdn2;
215 int ret;
216 u16 data[RTC_OFFSET_COUNT];
217
218 mutex_lock(&rtc->lock);
219 ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_IRQ_EN, &irqen);
220 if (ret < 0)
221 goto err_exit;
222 ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_PDN2, &pdn2);
223 if (ret < 0)
224 goto err_exit;
225
226 ret = regmap_bulk_read(rtc->regmap, rtc->addr_base + RTC_AL_SEC,
227 data, RTC_OFFSET_COUNT);
228 if (ret < 0)
229 goto err_exit;
230
231 alm->enabled = !!(irqen & RTC_IRQ_EN_AL);
232 alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM);
233 mutex_unlock(&rtc->lock);
234
235 tm->tm_sec = data[RTC_OFFSET_SEC];
236 tm->tm_min = data[RTC_OFFSET_MIN];
237 tm->tm_hour = data[RTC_OFFSET_HOUR];
238 tm->tm_mday = data[RTC_OFFSET_DOM];
239 tm->tm_mon = data[RTC_OFFSET_MTH];
240 tm->tm_year = data[RTC_OFFSET_YEAR];
241
242 tm->tm_year += RTC_MIN_YEAR_OFFSET;
243 tm->tm_mon--;
244
245 return 0;
246err_exit:
247 mutex_unlock(&rtc->lock);
248 return ret;
249}
250
251static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
252{
253 struct rtc_time *tm = &alm->time;
254 struct mt6397_rtc *rtc = dev_get_drvdata(dev);
255 int ret;
256 u16 data[RTC_OFFSET_COUNT];
257
258 tm->tm_year -= RTC_MIN_YEAR_OFFSET;
259 tm->tm_mon++;
260
261 data[RTC_OFFSET_SEC] = tm->tm_sec;
262 data[RTC_OFFSET_MIN] = tm->tm_min;
263 data[RTC_OFFSET_HOUR] = tm->tm_hour;
264 data[RTC_OFFSET_DOM] = tm->tm_mday;
265 data[RTC_OFFSET_MTH] = tm->tm_mon;
266 data[RTC_OFFSET_YEAR] = tm->tm_year;
267
268 mutex_lock(&rtc->lock);
269 if (alm->enabled) {
270 ret = regmap_bulk_write(rtc->regmap,
271 rtc->addr_base + RTC_AL_SEC,
272 data, RTC_OFFSET_COUNT);
273 if (ret < 0)
274 goto exit;
275 ret = regmap_write(rtc->regmap, rtc->addr_base + RTC_AL_MASK,
276 RTC_AL_MASK_DOW);
277 if (ret < 0)
278 goto exit;
279 ret = regmap_update_bits(rtc->regmap,
280 rtc->addr_base + RTC_IRQ_EN,
281 RTC_IRQ_EN_ONESHOT_AL,
282 RTC_IRQ_EN_ONESHOT_AL);
283 if (ret < 0)
284 goto exit;
285 } else {
286 ret = regmap_update_bits(rtc->regmap,
287 rtc->addr_base + RTC_IRQ_EN,
288 RTC_IRQ_EN_ONESHOT_AL, 0);
289 if (ret < 0)
290 goto exit;
291 }
292
293 /* All alarm time register write to hardware after calling
294 * mtk_rtc_write_trigger. This can avoid race condition if alarm
295 * occur happen during writing alarm time register.
296 */
297 ret = mtk_rtc_write_trigger(rtc);
298exit:
299 mutex_unlock(&rtc->lock);
300 return ret;
301}
302
303static struct rtc_class_ops mtk_rtc_ops = {
304 .read_time = mtk_rtc_read_time,
305 .set_time = mtk_rtc_set_time,
306 .read_alarm = mtk_rtc_read_alarm,
307 .set_alarm = mtk_rtc_set_alarm,
308};
309
310static int mtk_rtc_probe(struct platform_device *pdev)
311{
312 struct resource *res;
313 struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent);
314 struct mt6397_rtc *rtc;
315 int ret;
316
317 rtc = devm_kzalloc(&pdev->dev, sizeof(struct mt6397_rtc), GFP_KERNEL);
318 if (!rtc)
319 return -ENOMEM;
320
321 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
322 rtc->addr_base = res->start;
323
324 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
325 rtc->irq = irq_create_mapping(mt6397_chip->irq_domain, res->start);
326 if (rtc->irq <= 0)
327 return -EINVAL;
328
329 rtc->regmap = mt6397_chip->regmap;
330 rtc->dev = &pdev->dev;
331 mutex_init(&rtc->lock);
332
333 platform_set_drvdata(pdev, rtc);
334
335 ret = request_threaded_irq(rtc->irq, NULL,
336 mtk_rtc_irq_handler_thread,
337 IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
338 "mt6397-rtc", rtc);
339 if (ret) {
340 dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
341 rtc->irq, ret);
342 goto out_dispose_irq;
343 }
344
345 rtc->rtc_dev = rtc_device_register("mt6397-rtc", &pdev->dev,
346 &mtk_rtc_ops, THIS_MODULE);
347 if (IS_ERR(rtc->rtc_dev)) {
348 dev_err(&pdev->dev, "register rtc device failed\n");
349 ret = PTR_ERR(rtc->rtc_dev);
350 goto out_free_irq;
351 }
352
353 device_init_wakeup(&pdev->dev, 1);
354
355 return 0;
356
357out_free_irq:
358 free_irq(rtc->irq, rtc->rtc_dev);
359out_dispose_irq:
360 irq_dispose_mapping(rtc->irq);
361 return ret;
362}
363
364static int mtk_rtc_remove(struct platform_device *pdev)
365{
366 struct mt6397_rtc *rtc = platform_get_drvdata(pdev);
367
368 rtc_device_unregister(rtc->rtc_dev);
369 free_irq(rtc->irq, rtc->rtc_dev);
370 irq_dispose_mapping(rtc->irq);
371
372 return 0;
373}
374
375static const struct of_device_id mt6397_rtc_of_match[] = {
376 { .compatible = "mediatek,mt6397-rtc", },
377 { }
378};
379
380static struct platform_driver mtk_rtc_driver = {
381 .driver = {
382 .name = "mt6397-rtc",
383 .of_match_table = mt6397_rtc_of_match,
384 },
385 .probe = mtk_rtc_probe,
386 .remove = mtk_rtc_remove,
387};
388
389module_platform_driver(mtk_rtc_driver);
390
391MODULE_LICENSE("GPL v2");
392MODULE_AUTHOR("Tianping Fang <tianping.fang@mediatek.com>");
393MODULE_DESCRIPTION("RTC Driver for MediaTek MT6397 PMIC");
394MODULE_ALIAS("platform:mt6397-rtc");