linux/drivers/rtc/rtc-s3c.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* drivers/rtc/rtc-s3c.c
   3 *
   4 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
   5 *              http://www.samsung.com/
   6 *
   7 * Copyright (c) 2004,2006 Simtec Electronics
   8 *      Ben Dooks, <ben@simtec.co.uk>
   9 *      http://armlinux.simtec.co.uk/
  10 *
  11 * S3C2410/S3C2440/S3C24XX Internal RTC Driver
  12*/
  13
  14#include <linux/module.h>
  15#include <linux/fs.h>
  16#include <linux/string.h>
  17#include <linux/init.h>
  18#include <linux/platform_device.h>
  19#include <linux/interrupt.h>
  20#include <linux/rtc.h>
  21#include <linux/bcd.h>
  22#include <linux/clk.h>
  23#include <linux/log2.h>
  24#include <linux/slab.h>
  25#include <linux/of.h>
  26#include <linux/of_device.h>
  27#include <linux/uaccess.h>
  28#include <linux/io.h>
  29
  30#include <asm/irq.h>
  31#include "rtc-s3c.h"
  32
  33struct s3c_rtc {
  34        struct device *dev;
  35        struct rtc_device *rtc;
  36
  37        void __iomem *base;
  38        struct clk *rtc_clk;
  39        struct clk *rtc_src_clk;
  40        bool alarm_enabled;
  41
  42        const struct s3c_rtc_data *data;
  43
  44        int irq_alarm;
  45        spinlock_t alarm_lock;
  46
  47        bool wake_en;
  48};
  49
  50struct s3c_rtc_data {
  51        bool needs_src_clk;
  52
  53        void (*irq_handler) (struct s3c_rtc *info, int mask);
  54        void (*enable) (struct s3c_rtc *info);
  55        void (*disable) (struct s3c_rtc *info);
  56};
  57
  58static int s3c_rtc_enable_clk(struct s3c_rtc *info)
  59{
  60        int ret;
  61
  62        ret = clk_enable(info->rtc_clk);
  63        if (ret)
  64                return ret;
  65
  66        if (info->data->needs_src_clk) {
  67                ret = clk_enable(info->rtc_src_clk);
  68                if (ret) {
  69                        clk_disable(info->rtc_clk);
  70                        return ret;
  71                }
  72        }
  73        return 0;
  74}
  75
  76static void s3c_rtc_disable_clk(struct s3c_rtc *info)
  77{
  78        if (info->data->needs_src_clk)
  79                clk_disable(info->rtc_src_clk);
  80        clk_disable(info->rtc_clk);
  81}
  82
  83/* IRQ Handler */
  84static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
  85{
  86        struct s3c_rtc *info = (struct s3c_rtc *)id;
  87
  88        if (info->data->irq_handler)
  89                info->data->irq_handler(info, S3C2410_INTP_ALM);
  90
  91        return IRQ_HANDLED;
  92}
  93
  94/* Update control registers */
  95static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
  96{
  97        struct s3c_rtc *info = dev_get_drvdata(dev);
  98        unsigned long flags;
  99        unsigned int tmp;
 100        int ret;
 101
 102        dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
 103
 104        ret = s3c_rtc_enable_clk(info);
 105        if (ret)
 106                return ret;
 107
 108        tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
 109
 110        if (enabled)
 111                tmp |= S3C2410_RTCALM_ALMEN;
 112
 113        writeb(tmp, info->base + S3C2410_RTCALM);
 114
 115        spin_lock_irqsave(&info->alarm_lock, flags);
 116
 117        if (info->alarm_enabled && !enabled)
 118                s3c_rtc_disable_clk(info);
 119        else if (!info->alarm_enabled && enabled)
 120                ret = s3c_rtc_enable_clk(info);
 121
 122        info->alarm_enabled = enabled;
 123        spin_unlock_irqrestore(&info->alarm_lock, flags);
 124
 125        s3c_rtc_disable_clk(info);
 126
 127        return ret;
 128}
 129
 130/* Time read/write */
 131static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 132{
 133        struct s3c_rtc *info = dev_get_drvdata(dev);
 134        unsigned int have_retried = 0;
 135        int ret;
 136
 137        ret = s3c_rtc_enable_clk(info);
 138        if (ret)
 139                return ret;
 140
 141retry_get_time:
 142        rtc_tm->tm_min  = readb(info->base + S3C2410_RTCMIN);
 143        rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
 144        rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
 145        rtc_tm->tm_mon  = readb(info->base + S3C2410_RTCMON);
 146        rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
 147        rtc_tm->tm_sec  = readb(info->base + S3C2410_RTCSEC);
 148
 149        /* the only way to work out whether the system was mid-update
 150         * when we read it is to check the second counter, and if it
 151         * is zero, then we re-try the entire read
 152         */
 153
 154        if (rtc_tm->tm_sec == 0 && !have_retried) {
 155                have_retried = 1;
 156                goto retry_get_time;
 157        }
 158
 159        rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
 160        rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
 161        rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
 162        rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
 163        rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
 164        rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
 165
 166        s3c_rtc_disable_clk(info);
 167
 168        rtc_tm->tm_year += 100;
 169        rtc_tm->tm_mon -= 1;
 170
 171        dev_dbg(dev, "read time %ptR\n", rtc_tm);
 172        return 0;
 173}
 174
 175static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
 176{
 177        struct s3c_rtc *info = dev_get_drvdata(dev);
 178        int year = tm->tm_year - 100;
 179        int ret;
 180
 181        dev_dbg(dev, "set time %ptR\n", tm);
 182
 183        /* we get around y2k by simply not supporting it */
 184
 185        if (year < 0 || year >= 100) {
 186                dev_err(dev, "rtc only supports 100 years\n");
 187                return -EINVAL;
 188        }
 189
 190        ret = s3c_rtc_enable_clk(info);
 191        if (ret)
 192                return ret;
 193
 194        writeb(bin2bcd(tm->tm_sec),  info->base + S3C2410_RTCSEC);
 195        writeb(bin2bcd(tm->tm_min),  info->base + S3C2410_RTCMIN);
 196        writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
 197        writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
 198        writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON);
 199        writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR);
 200
 201        s3c_rtc_disable_clk(info);
 202
 203        return 0;
 204}
 205
 206static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
 207{
 208        struct s3c_rtc *info = dev_get_drvdata(dev);
 209        struct rtc_time *alm_tm = &alrm->time;
 210        unsigned int alm_en;
 211        int ret;
 212
 213        ret = s3c_rtc_enable_clk(info);
 214        if (ret)
 215                return ret;
 216
 217        alm_tm->tm_sec  = readb(info->base + S3C2410_ALMSEC);
 218        alm_tm->tm_min  = readb(info->base + S3C2410_ALMMIN);
 219        alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR);
 220        alm_tm->tm_mon  = readb(info->base + S3C2410_ALMMON);
 221        alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE);
 222        alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR);
 223
 224        alm_en = readb(info->base + S3C2410_RTCALM);
 225
 226        s3c_rtc_disable_clk(info);
 227
 228        alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
 229
 230        dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm);
 231
 232        /* decode the alarm enable field */
 233        if (alm_en & S3C2410_RTCALM_SECEN)
 234                alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
 235
 236        if (alm_en & S3C2410_RTCALM_MINEN)
 237                alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
 238
 239        if (alm_en & S3C2410_RTCALM_HOUREN)
 240                alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
 241
 242        if (alm_en & S3C2410_RTCALM_DAYEN)
 243                alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
 244
 245        if (alm_en & S3C2410_RTCALM_MONEN) {
 246                alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
 247                alm_tm->tm_mon -= 1;
 248        }
 249
 250        if (alm_en & S3C2410_RTCALM_YEAREN)
 251                alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
 252
 253        return 0;
 254}
 255
 256static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 257{
 258        struct s3c_rtc *info = dev_get_drvdata(dev);
 259        struct rtc_time *tm = &alrm->time;
 260        unsigned int alrm_en;
 261        int ret;
 262
 263        dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm);
 264
 265        ret = s3c_rtc_enable_clk(info);
 266        if (ret)
 267                return ret;
 268
 269        alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
 270        writeb(0x00, info->base + S3C2410_RTCALM);
 271
 272        if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
 273                alrm_en |= S3C2410_RTCALM_SECEN;
 274                writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC);
 275        }
 276
 277        if (tm->tm_min < 60 && tm->tm_min >= 0) {
 278                alrm_en |= S3C2410_RTCALM_MINEN;
 279                writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN);
 280        }
 281
 282        if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
 283                alrm_en |= S3C2410_RTCALM_HOUREN;
 284                writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
 285        }
 286
 287        if (tm->tm_mon < 12 && tm->tm_mon >= 0) {
 288                alrm_en |= S3C2410_RTCALM_MONEN;
 289                writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON);
 290        }
 291
 292        if (tm->tm_mday <= 31 && tm->tm_mday >= 1) {
 293                alrm_en |= S3C2410_RTCALM_DAYEN;
 294                writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_ALMDATE);
 295        }
 296
 297        dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
 298
 299        writeb(alrm_en, info->base + S3C2410_RTCALM);
 300
 301        s3c_rtc_setaie(dev, alrm->enabled);
 302
 303        s3c_rtc_disable_clk(info);
 304
 305        return 0;
 306}
 307
 308static const struct rtc_class_ops s3c_rtcops = {
 309        .read_time      = s3c_rtc_gettime,
 310        .set_time       = s3c_rtc_settime,
 311        .read_alarm     = s3c_rtc_getalarm,
 312        .set_alarm      = s3c_rtc_setalarm,
 313        .alarm_irq_enable = s3c_rtc_setaie,
 314};
 315
 316static void s3c24xx_rtc_enable(struct s3c_rtc *info)
 317{
 318        unsigned int con, tmp;
 319
 320        con = readw(info->base + S3C2410_RTCCON);
 321        /* re-enable the device, and check it is ok */
 322        if ((con & S3C2410_RTCCON_RTCEN) == 0) {
 323                dev_info(info->dev, "rtc disabled, re-enabling\n");
 324
 325                tmp = readw(info->base + S3C2410_RTCCON);
 326                writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
 327        }
 328
 329        if (con & S3C2410_RTCCON_CNTSEL) {
 330                dev_info(info->dev, "removing RTCCON_CNTSEL\n");
 331
 332                tmp = readw(info->base + S3C2410_RTCCON);
 333                writew(tmp & ~S3C2410_RTCCON_CNTSEL,
 334                       info->base + S3C2410_RTCCON);
 335        }
 336
 337        if (con & S3C2410_RTCCON_CLKRST) {
 338                dev_info(info->dev, "removing RTCCON_CLKRST\n");
 339
 340                tmp = readw(info->base + S3C2410_RTCCON);
 341                writew(tmp & ~S3C2410_RTCCON_CLKRST,
 342                       info->base + S3C2410_RTCCON);
 343        }
 344}
 345
 346static void s3c24xx_rtc_disable(struct s3c_rtc *info)
 347{
 348        unsigned int con;
 349
 350        con = readw(info->base + S3C2410_RTCCON);
 351        con &= ~S3C2410_RTCCON_RTCEN;
 352        writew(con, info->base + S3C2410_RTCCON);
 353
 354        con = readb(info->base + S3C2410_TICNT);
 355        con &= ~S3C2410_TICNT_ENABLE;
 356        writeb(con, info->base + S3C2410_TICNT);
 357}
 358
 359static void s3c6410_rtc_disable(struct s3c_rtc *info)
 360{
 361        unsigned int con;
 362
 363        con = readw(info->base + S3C2410_RTCCON);
 364        con &= ~S3C64XX_RTCCON_TICEN;
 365        con &= ~S3C2410_RTCCON_RTCEN;
 366        writew(con, info->base + S3C2410_RTCCON);
 367}
 368
 369static int s3c_rtc_remove(struct platform_device *pdev)
 370{
 371        struct s3c_rtc *info = platform_get_drvdata(pdev);
 372
 373        s3c_rtc_setaie(info->dev, 0);
 374
 375        if (info->data->needs_src_clk)
 376                clk_unprepare(info->rtc_src_clk);
 377        clk_unprepare(info->rtc_clk);
 378
 379        return 0;
 380}
 381
 382static int s3c_rtc_probe(struct platform_device *pdev)
 383{
 384        struct s3c_rtc *info = NULL;
 385        int ret;
 386
 387        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 388        if (!info)
 389                return -ENOMEM;
 390
 391        info->dev = &pdev->dev;
 392        info->data = of_device_get_match_data(&pdev->dev);
 393        if (!info->data) {
 394                dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
 395                return -EINVAL;
 396        }
 397        spin_lock_init(&info->alarm_lock);
 398
 399        platform_set_drvdata(pdev, info);
 400
 401        info->irq_alarm = platform_get_irq(pdev, 0);
 402        if (info->irq_alarm < 0)
 403                return info->irq_alarm;
 404
 405        dev_dbg(&pdev->dev, "s3c2410_rtc: alarm irq %d\n", info->irq_alarm);
 406
 407        /* get the memory region */
 408        info->base = devm_platform_ioremap_resource(pdev, 0);
 409        if (IS_ERR(info->base))
 410                return PTR_ERR(info->base);
 411
 412        info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
 413        if (IS_ERR(info->rtc_clk)) {
 414                ret = PTR_ERR(info->rtc_clk);
 415                if (ret != -EPROBE_DEFER)
 416                        dev_err(&pdev->dev, "failed to find rtc clock\n");
 417                else
 418                        dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
 419                return ret;
 420        }
 421        ret = clk_prepare_enable(info->rtc_clk);
 422        if (ret)
 423                return ret;
 424
 425        if (info->data->needs_src_clk) {
 426                info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
 427                if (IS_ERR(info->rtc_src_clk)) {
 428                        ret = dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_src_clk),
 429                                            "failed to find rtc source clock\n");
 430                        goto err_src_clk;
 431                }
 432                ret = clk_prepare_enable(info->rtc_src_clk);
 433                if (ret)
 434                        goto err_src_clk;
 435        }
 436
 437        /* disable RTC enable bits potentially set by the bootloader */
 438        if (info->data->disable)
 439                info->data->disable(info);
 440
 441        /* check to see if everything is setup correctly */
 442        if (info->data->enable)
 443                info->data->enable(info);
 444
 445        dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
 446                readw(info->base + S3C2410_RTCCON));
 447
 448        device_init_wakeup(&pdev->dev, 1);
 449
 450        /* register RTC and exit */
 451        info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
 452                                             THIS_MODULE);
 453        if (IS_ERR(info->rtc)) {
 454                dev_err(&pdev->dev, "cannot attach rtc\n");
 455                ret = PTR_ERR(info->rtc);
 456                goto err_nortc;
 457        }
 458
 459        ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
 460                               0, "s3c2410-rtc alarm", info);
 461        if (ret) {
 462                dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
 463                goto err_nortc;
 464        }
 465
 466        s3c_rtc_disable_clk(info);
 467
 468        return 0;
 469
 470err_nortc:
 471        if (info->data->disable)
 472                info->data->disable(info);
 473
 474        if (info->data->needs_src_clk)
 475                clk_disable_unprepare(info->rtc_src_clk);
 476err_src_clk:
 477        clk_disable_unprepare(info->rtc_clk);
 478
 479        return ret;
 480}
 481
 482#ifdef CONFIG_PM_SLEEP
 483
 484static int s3c_rtc_suspend(struct device *dev)
 485{
 486        struct s3c_rtc *info = dev_get_drvdata(dev);
 487        int ret;
 488
 489        ret = s3c_rtc_enable_clk(info);
 490        if (ret)
 491                return ret;
 492
 493        if (info->data->disable)
 494                info->data->disable(info);
 495
 496        if (device_may_wakeup(dev) && !info->wake_en) {
 497                if (enable_irq_wake(info->irq_alarm) == 0)
 498                        info->wake_en = true;
 499                else
 500                        dev_err(dev, "enable_irq_wake failed\n");
 501        }
 502
 503        return 0;
 504}
 505
 506static int s3c_rtc_resume(struct device *dev)
 507{
 508        struct s3c_rtc *info = dev_get_drvdata(dev);
 509
 510        if (info->data->enable)
 511                info->data->enable(info);
 512
 513        s3c_rtc_disable_clk(info);
 514
 515        if (device_may_wakeup(dev) && info->wake_en) {
 516                disable_irq_wake(info->irq_alarm);
 517                info->wake_en = false;
 518        }
 519
 520        return 0;
 521}
 522#endif
 523static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
 524
 525static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
 526{
 527        rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
 528}
 529
 530static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
 531{
 532        rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
 533        writeb(mask, info->base + S3C2410_INTP);
 534}
 535
 536static struct s3c_rtc_data const s3c2410_rtc_data = {
 537        .irq_handler            = s3c24xx_rtc_irq,
 538        .enable                 = s3c24xx_rtc_enable,
 539        .disable                = s3c24xx_rtc_disable,
 540};
 541
 542static struct s3c_rtc_data const s3c2416_rtc_data = {
 543        .irq_handler            = s3c24xx_rtc_irq,
 544        .enable                 = s3c24xx_rtc_enable,
 545        .disable                = s3c24xx_rtc_disable,
 546};
 547
 548static struct s3c_rtc_data const s3c2443_rtc_data = {
 549        .irq_handler            = s3c24xx_rtc_irq,
 550        .enable                 = s3c24xx_rtc_enable,
 551        .disable                = s3c24xx_rtc_disable,
 552};
 553
 554static struct s3c_rtc_data const s3c6410_rtc_data = {
 555        .needs_src_clk          = true,
 556        .irq_handler            = s3c6410_rtc_irq,
 557        .enable                 = s3c24xx_rtc_enable,
 558        .disable                = s3c6410_rtc_disable,
 559};
 560
 561static const __maybe_unused struct of_device_id s3c_rtc_dt_match[] = {
 562        {
 563                .compatible = "samsung,s3c2410-rtc",
 564                .data = &s3c2410_rtc_data,
 565        }, {
 566                .compatible = "samsung,s3c2416-rtc",
 567                .data = &s3c2416_rtc_data,
 568        }, {
 569                .compatible = "samsung,s3c2443-rtc",
 570                .data = &s3c2443_rtc_data,
 571        }, {
 572                .compatible = "samsung,s3c6410-rtc",
 573                .data = &s3c6410_rtc_data,
 574        }, {
 575                .compatible = "samsung,exynos3250-rtc",
 576                .data = &s3c6410_rtc_data,
 577        },
 578        { /* sentinel */ },
 579};
 580MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
 581
 582static struct platform_driver s3c_rtc_driver = {
 583        .probe          = s3c_rtc_probe,
 584        .remove         = s3c_rtc_remove,
 585        .driver         = {
 586                .name   = "s3c-rtc",
 587                .pm     = &s3c_rtc_pm_ops,
 588                .of_match_table = of_match_ptr(s3c_rtc_dt_match),
 589        },
 590};
 591module_platform_driver(s3c_rtc_driver);
 592
 593MODULE_DESCRIPTION("Samsung S3C RTC Driver");
 594MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 595MODULE_LICENSE("GPL");
 596MODULE_ALIAS("platform:s3c2410-rtc");
 597