0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/module.h>
0015 #include <linux/fs.h>
0016 #include <linux/string.h>
0017 #include <linux/init.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/rtc.h>
0021 #include <linux/bcd.h>
0022 #include <linux/clk.h>
0023 #include <linux/log2.h>
0024 #include <linux/slab.h>
0025 #include <linux/of.h>
0026 #include <linux/of_device.h>
0027 #include <linux/uaccess.h>
0028 #include <linux/io.h>
0029
0030 #include <asm/irq.h>
0031 #include "rtc-s3c.h"
0032
0033 struct s3c_rtc {
0034 struct device *dev;
0035 struct rtc_device *rtc;
0036
0037 void __iomem *base;
0038 struct clk *rtc_clk;
0039 struct clk *rtc_src_clk;
0040 bool alarm_enabled;
0041
0042 const struct s3c_rtc_data *data;
0043
0044 int irq_alarm;
0045 spinlock_t alarm_lock;
0046
0047 bool wake_en;
0048 };
0049
0050 struct s3c_rtc_data {
0051 bool needs_src_clk;
0052
0053 void (*irq_handler) (struct s3c_rtc *info, int mask);
0054 void (*enable) (struct s3c_rtc *info);
0055 void (*disable) (struct s3c_rtc *info);
0056 };
0057
0058 static int s3c_rtc_enable_clk(struct s3c_rtc *info)
0059 {
0060 int ret;
0061
0062 ret = clk_enable(info->rtc_clk);
0063 if (ret)
0064 return ret;
0065
0066 if (info->data->needs_src_clk) {
0067 ret = clk_enable(info->rtc_src_clk);
0068 if (ret) {
0069 clk_disable(info->rtc_clk);
0070 return ret;
0071 }
0072 }
0073 return 0;
0074 }
0075
0076 static void s3c_rtc_disable_clk(struct s3c_rtc *info)
0077 {
0078 if (info->data->needs_src_clk)
0079 clk_disable(info->rtc_src_clk);
0080 clk_disable(info->rtc_clk);
0081 }
0082
0083
0084 static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
0085 {
0086 struct s3c_rtc *info = (struct s3c_rtc *)id;
0087
0088 if (info->data->irq_handler)
0089 info->data->irq_handler(info, S3C2410_INTP_ALM);
0090
0091 return IRQ_HANDLED;
0092 }
0093
0094
0095 static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
0096 {
0097 struct s3c_rtc *info = dev_get_drvdata(dev);
0098 unsigned long flags;
0099 unsigned int tmp;
0100 int ret;
0101
0102 dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
0103
0104 ret = s3c_rtc_enable_clk(info);
0105 if (ret)
0106 return ret;
0107
0108 tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
0109
0110 if (enabled)
0111 tmp |= S3C2410_RTCALM_ALMEN;
0112
0113 writeb(tmp, info->base + S3C2410_RTCALM);
0114
0115 spin_lock_irqsave(&info->alarm_lock, flags);
0116
0117 if (info->alarm_enabled && !enabled)
0118 s3c_rtc_disable_clk(info);
0119 else if (!info->alarm_enabled && enabled)
0120 ret = s3c_rtc_enable_clk(info);
0121
0122 info->alarm_enabled = enabled;
0123 spin_unlock_irqrestore(&info->alarm_lock, flags);
0124
0125 s3c_rtc_disable_clk(info);
0126
0127 return ret;
0128 }
0129
0130
0131 static int s3c_rtc_read_time(struct s3c_rtc *info, struct rtc_time *tm)
0132 {
0133 unsigned int have_retried = 0;
0134 int ret;
0135
0136 ret = s3c_rtc_enable_clk(info);
0137 if (ret)
0138 return ret;
0139
0140 retry_get_time:
0141 tm->tm_min = readb(info->base + S3C2410_RTCMIN);
0142 tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
0143 tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
0144 tm->tm_mon = readb(info->base + S3C2410_RTCMON);
0145 tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
0146 tm->tm_sec = readb(info->base + S3C2410_RTCSEC);
0147
0148
0149
0150
0151
0152
0153 if (tm->tm_sec == 0 && !have_retried) {
0154 have_retried = 1;
0155 goto retry_get_time;
0156 }
0157
0158 s3c_rtc_disable_clk(info);
0159
0160 tm->tm_sec = bcd2bin(tm->tm_sec);
0161 tm->tm_min = bcd2bin(tm->tm_min);
0162 tm->tm_hour = bcd2bin(tm->tm_hour);
0163 tm->tm_mday = bcd2bin(tm->tm_mday);
0164 tm->tm_mon = bcd2bin(tm->tm_mon);
0165 tm->tm_year = bcd2bin(tm->tm_year);
0166
0167 return 0;
0168 }
0169
0170
0171 static int s3c_rtc_write_time(struct s3c_rtc *info, const struct rtc_time *tm)
0172 {
0173 int ret;
0174
0175 ret = s3c_rtc_enable_clk(info);
0176 if (ret)
0177 return ret;
0178
0179 writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC);
0180 writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN);
0181 writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
0182 writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
0183 writeb(bin2bcd(tm->tm_mon), info->base + S3C2410_RTCMON);
0184 writeb(bin2bcd(tm->tm_year), info->base + S3C2410_RTCYEAR);
0185
0186 s3c_rtc_disable_clk(info);
0187
0188 return 0;
0189 }
0190
0191 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *tm)
0192 {
0193 struct s3c_rtc *info = dev_get_drvdata(dev);
0194 int ret;
0195
0196 ret = s3c_rtc_read_time(info, tm);
0197 if (ret)
0198 return ret;
0199
0200
0201 tm->tm_year += 100;
0202 tm->tm_mon -= 1;
0203
0204 dev_dbg(dev, "read time %ptR\n", tm);
0205 return 0;
0206 }
0207
0208 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
0209 {
0210 struct s3c_rtc *info = dev_get_drvdata(dev);
0211 struct rtc_time rtc_tm = *tm;
0212
0213 dev_dbg(dev, "set time %ptR\n", tm);
0214
0215
0216
0217
0218
0219 rtc_tm.tm_year -= 100;
0220 rtc_tm.tm_mon += 1;
0221
0222 return s3c_rtc_write_time(info, &rtc_tm);
0223 }
0224
0225 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
0226 {
0227 struct s3c_rtc *info = dev_get_drvdata(dev);
0228 struct rtc_time *alm_tm = &alrm->time;
0229 unsigned int alm_en;
0230 int ret;
0231
0232 ret = s3c_rtc_enable_clk(info);
0233 if (ret)
0234 return ret;
0235
0236 alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC);
0237 alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN);
0238 alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR);
0239 alm_tm->tm_mon = readb(info->base + S3C2410_ALMMON);
0240 alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE);
0241 alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR);
0242
0243 alm_en = readb(info->base + S3C2410_RTCALM);
0244
0245 s3c_rtc_disable_clk(info);
0246
0247 alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
0248
0249 dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm);
0250
0251
0252 if (alm_en & S3C2410_RTCALM_SECEN)
0253 alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
0254
0255 if (alm_en & S3C2410_RTCALM_MINEN)
0256 alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
0257
0258 if (alm_en & S3C2410_RTCALM_HOUREN)
0259 alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
0260
0261 if (alm_en & S3C2410_RTCALM_DAYEN)
0262 alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
0263
0264 if (alm_en & S3C2410_RTCALM_MONEN) {
0265 alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
0266 alm_tm->tm_mon -= 1;
0267 }
0268
0269 if (alm_en & S3C2410_RTCALM_YEAREN)
0270 alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
0271
0272 return 0;
0273 }
0274
0275 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
0276 {
0277 struct s3c_rtc *info = dev_get_drvdata(dev);
0278 struct rtc_time *tm = &alrm->time;
0279 unsigned int alrm_en;
0280 int ret;
0281
0282 dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm);
0283
0284 ret = s3c_rtc_enable_clk(info);
0285 if (ret)
0286 return ret;
0287
0288 alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
0289 writeb(0x00, info->base + S3C2410_RTCALM);
0290
0291 if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
0292 alrm_en |= S3C2410_RTCALM_SECEN;
0293 writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC);
0294 }
0295
0296 if (tm->tm_min < 60 && tm->tm_min >= 0) {
0297 alrm_en |= S3C2410_RTCALM_MINEN;
0298 writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN);
0299 }
0300
0301 if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
0302 alrm_en |= S3C2410_RTCALM_HOUREN;
0303 writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
0304 }
0305
0306 if (tm->tm_mon < 12 && tm->tm_mon >= 0) {
0307 alrm_en |= S3C2410_RTCALM_MONEN;
0308 writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON);
0309 }
0310
0311 if (tm->tm_mday <= 31 && tm->tm_mday >= 1) {
0312 alrm_en |= S3C2410_RTCALM_DAYEN;
0313 writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_ALMDATE);
0314 }
0315
0316 dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
0317
0318 writeb(alrm_en, info->base + S3C2410_RTCALM);
0319
0320 s3c_rtc_setaie(dev, alrm->enabled);
0321
0322 s3c_rtc_disable_clk(info);
0323
0324 return 0;
0325 }
0326
0327 static const struct rtc_class_ops s3c_rtcops = {
0328 .read_time = s3c_rtc_gettime,
0329 .set_time = s3c_rtc_settime,
0330 .read_alarm = s3c_rtc_getalarm,
0331 .set_alarm = s3c_rtc_setalarm,
0332 .alarm_irq_enable = s3c_rtc_setaie,
0333 };
0334
0335 static void s3c24xx_rtc_enable(struct s3c_rtc *info)
0336 {
0337 unsigned int con, tmp;
0338
0339 con = readw(info->base + S3C2410_RTCCON);
0340
0341 if ((con & S3C2410_RTCCON_RTCEN) == 0) {
0342 dev_info(info->dev, "rtc disabled, re-enabling\n");
0343
0344 tmp = readw(info->base + S3C2410_RTCCON);
0345 writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
0346 }
0347
0348 if (con & S3C2410_RTCCON_CNTSEL) {
0349 dev_info(info->dev, "removing RTCCON_CNTSEL\n");
0350
0351 tmp = readw(info->base + S3C2410_RTCCON);
0352 writew(tmp & ~S3C2410_RTCCON_CNTSEL,
0353 info->base + S3C2410_RTCCON);
0354 }
0355
0356 if (con & S3C2410_RTCCON_CLKRST) {
0357 dev_info(info->dev, "removing RTCCON_CLKRST\n");
0358
0359 tmp = readw(info->base + S3C2410_RTCCON);
0360 writew(tmp & ~S3C2410_RTCCON_CLKRST,
0361 info->base + S3C2410_RTCCON);
0362 }
0363 }
0364
0365 static void s3c24xx_rtc_disable(struct s3c_rtc *info)
0366 {
0367 unsigned int con;
0368
0369 con = readw(info->base + S3C2410_RTCCON);
0370 con &= ~S3C2410_RTCCON_RTCEN;
0371 writew(con, info->base + S3C2410_RTCCON);
0372
0373 con = readb(info->base + S3C2410_TICNT);
0374 con &= ~S3C2410_TICNT_ENABLE;
0375 writeb(con, info->base + S3C2410_TICNT);
0376 }
0377
0378 static void s3c6410_rtc_disable(struct s3c_rtc *info)
0379 {
0380 unsigned int con;
0381
0382 con = readw(info->base + S3C2410_RTCCON);
0383 con &= ~S3C64XX_RTCCON_TICEN;
0384 con &= ~S3C2410_RTCCON_RTCEN;
0385 writew(con, info->base + S3C2410_RTCCON);
0386 }
0387
0388 static int s3c_rtc_remove(struct platform_device *pdev)
0389 {
0390 struct s3c_rtc *info = platform_get_drvdata(pdev);
0391
0392 s3c_rtc_setaie(info->dev, 0);
0393
0394 if (info->data->needs_src_clk)
0395 clk_unprepare(info->rtc_src_clk);
0396 clk_unprepare(info->rtc_clk);
0397
0398 return 0;
0399 }
0400
0401 static int s3c_rtc_probe(struct platform_device *pdev)
0402 {
0403 struct s3c_rtc *info = NULL;
0404 int ret;
0405
0406 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
0407 if (!info)
0408 return -ENOMEM;
0409
0410 info->dev = &pdev->dev;
0411 info->data = of_device_get_match_data(&pdev->dev);
0412 if (!info->data) {
0413 dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
0414 return -EINVAL;
0415 }
0416 spin_lock_init(&info->alarm_lock);
0417
0418 platform_set_drvdata(pdev, info);
0419
0420 info->irq_alarm = platform_get_irq(pdev, 0);
0421 if (info->irq_alarm < 0)
0422 return info->irq_alarm;
0423
0424 dev_dbg(&pdev->dev, "s3c2410_rtc: alarm irq %d\n", info->irq_alarm);
0425
0426
0427 info->base = devm_platform_ioremap_resource(pdev, 0);
0428 if (IS_ERR(info->base))
0429 return PTR_ERR(info->base);
0430
0431 info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
0432 if (IS_ERR(info->rtc_clk)) {
0433 ret = PTR_ERR(info->rtc_clk);
0434 if (ret != -EPROBE_DEFER)
0435 dev_err(&pdev->dev, "failed to find rtc clock\n");
0436 else
0437 dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
0438 return ret;
0439 }
0440 ret = clk_prepare_enable(info->rtc_clk);
0441 if (ret)
0442 return ret;
0443
0444 if (info->data->needs_src_clk) {
0445 info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
0446 if (IS_ERR(info->rtc_src_clk)) {
0447 ret = dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_src_clk),
0448 "failed to find rtc source clock\n");
0449 goto err_src_clk;
0450 }
0451 ret = clk_prepare_enable(info->rtc_src_clk);
0452 if (ret)
0453 goto err_src_clk;
0454 }
0455
0456
0457 if (info->data->disable)
0458 info->data->disable(info);
0459
0460
0461 if (info->data->enable)
0462 info->data->enable(info);
0463
0464 dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
0465 readw(info->base + S3C2410_RTCCON));
0466
0467 device_init_wakeup(&pdev->dev, 1);
0468
0469 info->rtc = devm_rtc_allocate_device(&pdev->dev);
0470 if (IS_ERR(info->rtc)) {
0471 ret = PTR_ERR(info->rtc);
0472 goto err_nortc;
0473 }
0474
0475 info->rtc->ops = &s3c_rtcops;
0476 info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
0477 info->rtc->range_max = RTC_TIMESTAMP_END_2099;
0478
0479 ret = devm_rtc_register_device(info->rtc);
0480 if (ret)
0481 goto err_nortc;
0482
0483 ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
0484 0, "s3c2410-rtc alarm", info);
0485 if (ret) {
0486 dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
0487 goto err_nortc;
0488 }
0489
0490 s3c_rtc_disable_clk(info);
0491
0492 return 0;
0493
0494 err_nortc:
0495 if (info->data->disable)
0496 info->data->disable(info);
0497
0498 if (info->data->needs_src_clk)
0499 clk_disable_unprepare(info->rtc_src_clk);
0500 err_src_clk:
0501 clk_disable_unprepare(info->rtc_clk);
0502
0503 return ret;
0504 }
0505
0506 #ifdef CONFIG_PM_SLEEP
0507
0508 static int s3c_rtc_suspend(struct device *dev)
0509 {
0510 struct s3c_rtc *info = dev_get_drvdata(dev);
0511 int ret;
0512
0513 ret = s3c_rtc_enable_clk(info);
0514 if (ret)
0515 return ret;
0516
0517 if (info->data->disable)
0518 info->data->disable(info);
0519
0520 if (device_may_wakeup(dev) && !info->wake_en) {
0521 if (enable_irq_wake(info->irq_alarm) == 0)
0522 info->wake_en = true;
0523 else
0524 dev_err(dev, "enable_irq_wake failed\n");
0525 }
0526
0527 return 0;
0528 }
0529
0530 static int s3c_rtc_resume(struct device *dev)
0531 {
0532 struct s3c_rtc *info = dev_get_drvdata(dev);
0533
0534 if (info->data->enable)
0535 info->data->enable(info);
0536
0537 s3c_rtc_disable_clk(info);
0538
0539 if (device_may_wakeup(dev) && info->wake_en) {
0540 disable_irq_wake(info->irq_alarm);
0541 info->wake_en = false;
0542 }
0543
0544 return 0;
0545 }
0546 #endif
0547 static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
0548
0549 static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
0550 {
0551 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
0552 }
0553
0554 static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
0555 {
0556 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
0557 writeb(mask, info->base + S3C2410_INTP);
0558 }
0559
0560 static struct s3c_rtc_data const s3c2410_rtc_data = {
0561 .irq_handler = s3c24xx_rtc_irq,
0562 .enable = s3c24xx_rtc_enable,
0563 .disable = s3c24xx_rtc_disable,
0564 };
0565
0566 static struct s3c_rtc_data const s3c2416_rtc_data = {
0567 .irq_handler = s3c24xx_rtc_irq,
0568 .enable = s3c24xx_rtc_enable,
0569 .disable = s3c24xx_rtc_disable,
0570 };
0571
0572 static struct s3c_rtc_data const s3c2443_rtc_data = {
0573 .irq_handler = s3c24xx_rtc_irq,
0574 .enable = s3c24xx_rtc_enable,
0575 .disable = s3c24xx_rtc_disable,
0576 };
0577
0578 static struct s3c_rtc_data const s3c6410_rtc_data = {
0579 .needs_src_clk = true,
0580 .irq_handler = s3c6410_rtc_irq,
0581 .enable = s3c24xx_rtc_enable,
0582 .disable = s3c6410_rtc_disable,
0583 };
0584
0585 static const __maybe_unused struct of_device_id s3c_rtc_dt_match[] = {
0586 {
0587 .compatible = "samsung,s3c2410-rtc",
0588 .data = &s3c2410_rtc_data,
0589 }, {
0590 .compatible = "samsung,s3c2416-rtc",
0591 .data = &s3c2416_rtc_data,
0592 }, {
0593 .compatible = "samsung,s3c2443-rtc",
0594 .data = &s3c2443_rtc_data,
0595 }, {
0596 .compatible = "samsung,s3c6410-rtc",
0597 .data = &s3c6410_rtc_data,
0598 }, {
0599 .compatible = "samsung,exynos3250-rtc",
0600 .data = &s3c6410_rtc_data,
0601 },
0602 { },
0603 };
0604 MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
0605
0606 static struct platform_driver s3c_rtc_driver = {
0607 .probe = s3c_rtc_probe,
0608 .remove = s3c_rtc_remove,
0609 .driver = {
0610 .name = "s3c-rtc",
0611 .pm = &s3c_rtc_pm_ops,
0612 .of_match_table = of_match_ptr(s3c_rtc_dt_match),
0613 },
0614 };
0615 module_platform_driver(s3c_rtc_driver);
0616
0617 MODULE_DESCRIPTION("Samsung S3C RTC Driver");
0618 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
0619 MODULE_LICENSE("GPL");
0620 MODULE_ALIAS("platform:s3c2410-rtc");