linux/drivers/rtc/rtc-mpc5121.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Real-time clock driver for MPC5121
   4 *
   5 * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
   6 * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
   7 * Copyright 2011, Dmitry Eremin-Solenikov
   8 */
   9
  10#include <linux/init.h>
  11#include <linux/module.h>
  12#include <linux/rtc.h>
  13#include <linux/of.h>
  14#include <linux/of_address.h>
  15#include <linux/of_device.h>
  16#include <linux/of_irq.h>
  17#include <linux/of_platform.h>
  18#include <linux/io.h>
  19#include <linux/slab.h>
  20
  21struct mpc5121_rtc_regs {
  22        u8 set_time;            /* RTC + 0x00 */
  23        u8 hour_set;            /* RTC + 0x01 */
  24        u8 minute_set;          /* RTC + 0x02 */
  25        u8 second_set;          /* RTC + 0x03 */
  26
  27        u8 set_date;            /* RTC + 0x04 */
  28        u8 month_set;           /* RTC + 0x05 */
  29        u8 weekday_set;         /* RTC + 0x06 */
  30        u8 date_set;            /* RTC + 0x07 */
  31
  32        u8 write_sw;            /* RTC + 0x08 */
  33        u8 sw_set;              /* RTC + 0x09 */
  34        u16 year_set;           /* RTC + 0x0a */
  35
  36        u8 alm_enable;          /* RTC + 0x0c */
  37        u8 alm_hour_set;        /* RTC + 0x0d */
  38        u8 alm_min_set;         /* RTC + 0x0e */
  39        u8 int_enable;          /* RTC + 0x0f */
  40
  41        u8 reserved1;
  42        u8 hour;                /* RTC + 0x11 */
  43        u8 minute;              /* RTC + 0x12 */
  44        u8 second;              /* RTC + 0x13 */
  45
  46        u8 month;               /* RTC + 0x14 */
  47        u8 wday_mday;           /* RTC + 0x15 */
  48        u16 year;               /* RTC + 0x16 */
  49
  50        u8 int_alm;             /* RTC + 0x18 */
  51        u8 int_sw;              /* RTC + 0x19 */
  52        u8 alm_status;          /* RTC + 0x1a */
  53        u8 sw_minute;           /* RTC + 0x1b */
  54
  55        u8 bus_error_1;         /* RTC + 0x1c */
  56        u8 int_day;             /* RTC + 0x1d */
  57        u8 int_min;             /* RTC + 0x1e */
  58        u8 int_sec;             /* RTC + 0x1f */
  59
  60        /*
  61         * target_time:
  62         *      intended to be used for hibernation but hibernation
  63         *      does not work on silicon rev 1.5 so use it for non-volatile
  64         *      storage of offset between the actual_time register and linux
  65         *      time
  66         */
  67        u32 target_time;        /* RTC + 0x20 */
  68        /*
  69         * actual_time:
  70         *      readonly time since VBAT_RTC was last connected
  71         */
  72        u32 actual_time;        /* RTC + 0x24 */
  73        u32 keep_alive;         /* RTC + 0x28 */
  74};
  75
  76struct mpc5121_rtc_data {
  77        unsigned irq;
  78        unsigned irq_periodic;
  79        struct mpc5121_rtc_regs __iomem *regs;
  80        struct rtc_device *rtc;
  81        struct rtc_wkalrm wkalarm;
  82};
  83
  84/*
  85 * Update second/minute/hour registers.
  86 *
  87 * This is just so alarm will work.
  88 */
  89static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs,
  90                                   struct rtc_time *tm)
  91{
  92        out_8(&regs->second_set, tm->tm_sec);
  93        out_8(&regs->minute_set, tm->tm_min);
  94        out_8(&regs->hour_set, tm->tm_hour);
  95
  96        /* set time sequence */
  97        out_8(&regs->set_time, 0x1);
  98        out_8(&regs->set_time, 0x3);
  99        out_8(&regs->set_time, 0x1);
 100        out_8(&regs->set_time, 0x0);
 101}
 102
 103static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
 104{
 105        struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
 106        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 107        unsigned long now;
 108
 109        /*
 110         * linux time is actual_time plus the offset saved in target_time
 111         */
 112        now = in_be32(&regs->actual_time) + in_be32(&regs->target_time);
 113
 114        rtc_time64_to_tm(now, tm);
 115
 116        /*
 117         * update second minute hour registers
 118         * so alarms will work
 119         */
 120        mpc5121_rtc_update_smh(regs, tm);
 121
 122        return 0;
 123}
 124
 125static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
 126{
 127        struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
 128        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 129        unsigned long now;
 130
 131        /*
 132         * The actual_time register is read only so we write the offset
 133         * between it and linux time to the target_time register.
 134         */
 135        now = rtc_tm_to_time64(tm);
 136        out_be32(&regs->target_time, now - in_be32(&regs->actual_time));
 137
 138        /*
 139         * update second minute hour registers
 140         * so alarms will work
 141         */
 142        mpc5121_rtc_update_smh(regs, tm);
 143
 144        return 0;
 145}
 146
 147static int mpc5200_rtc_read_time(struct device *dev, struct rtc_time *tm)
 148{
 149        struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
 150        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 151        int tmp;
 152
 153        tm->tm_sec = in_8(&regs->second);
 154        tm->tm_min = in_8(&regs->minute);
 155
 156        /* 12 hour format? */
 157        if (in_8(&regs->hour) & 0x20)
 158                tm->tm_hour = (in_8(&regs->hour) >> 1) +
 159                        (in_8(&regs->hour) & 1 ? 12 : 0);
 160        else
 161                tm->tm_hour = in_8(&regs->hour);
 162
 163        tmp = in_8(&regs->wday_mday);
 164        tm->tm_mday = tmp & 0x1f;
 165        tm->tm_mon = in_8(&regs->month) - 1;
 166        tm->tm_year = in_be16(&regs->year) - 1900;
 167        tm->tm_wday = (tmp >> 5) % 7;
 168        tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
 169        tm->tm_isdst = 0;
 170
 171        return 0;
 172}
 173
 174static int mpc5200_rtc_set_time(struct device *dev, struct rtc_time *tm)
 175{
 176        struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
 177        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 178
 179        mpc5121_rtc_update_smh(regs, tm);
 180
 181        /* date */
 182        out_8(&regs->month_set, tm->tm_mon + 1);
 183        out_8(&regs->weekday_set, tm->tm_wday ? tm->tm_wday : 7);
 184        out_8(&regs->date_set, tm->tm_mday);
 185        out_be16(&regs->year_set, tm->tm_year + 1900);
 186
 187        /* set date sequence */
 188        out_8(&regs->set_date, 0x1);
 189        out_8(&regs->set_date, 0x3);
 190        out_8(&regs->set_date, 0x1);
 191        out_8(&regs->set_date, 0x0);
 192
 193        return 0;
 194}
 195
 196static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 197{
 198        struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
 199        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 200
 201        *alarm = rtc->wkalarm;
 202
 203        alarm->pending = in_8(&regs->alm_status);
 204
 205        return 0;
 206}
 207
 208static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 209{
 210        struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
 211        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 212
 213        alarm->time.tm_mday = -1;
 214        alarm->time.tm_mon = -1;
 215        alarm->time.tm_year = -1;
 216
 217        out_8(&regs->alm_min_set, alarm->time.tm_min);
 218        out_8(&regs->alm_hour_set, alarm->time.tm_hour);
 219
 220        out_8(&regs->alm_enable, alarm->enabled);
 221
 222        rtc->wkalarm = *alarm;
 223        return 0;
 224}
 225
 226static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
 227{
 228        struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
 229        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 230
 231        if (in_8(&regs->int_alm)) {
 232                /* acknowledge and clear status */
 233                out_8(&regs->int_alm, 1);
 234                out_8(&regs->alm_status, 1);
 235
 236                rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
 237                return IRQ_HANDLED;
 238        }
 239
 240        return IRQ_NONE;
 241}
 242
 243static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
 244{
 245        struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
 246        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 247
 248        if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)) {
 249                /* acknowledge */
 250                out_8(&regs->int_sec, 1);
 251
 252                rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
 253                return IRQ_HANDLED;
 254        }
 255
 256        return IRQ_NONE;
 257}
 258
 259static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
 260                                        unsigned int enabled)
 261{
 262        struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
 263        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 264        int val;
 265
 266        if (enabled)
 267                val = 1;
 268        else
 269                val = 0;
 270
 271        out_8(&regs->alm_enable, val);
 272        rtc->wkalarm.enabled = val;
 273
 274        return 0;
 275}
 276
 277static const struct rtc_class_ops mpc5121_rtc_ops = {
 278        .read_time = mpc5121_rtc_read_time,
 279        .set_time = mpc5121_rtc_set_time,
 280        .read_alarm = mpc5121_rtc_read_alarm,
 281        .set_alarm = mpc5121_rtc_set_alarm,
 282        .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
 283};
 284
 285static const struct rtc_class_ops mpc5200_rtc_ops = {
 286        .read_time = mpc5200_rtc_read_time,
 287        .set_time = mpc5200_rtc_set_time,
 288        .read_alarm = mpc5121_rtc_read_alarm,
 289        .set_alarm = mpc5121_rtc_set_alarm,
 290        .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
 291};
 292
 293static int mpc5121_rtc_probe(struct platform_device *op)
 294{
 295        struct mpc5121_rtc_data *rtc;
 296        int err = 0;
 297
 298        rtc = devm_kzalloc(&op->dev, sizeof(*rtc), GFP_KERNEL);
 299        if (!rtc)
 300                return -ENOMEM;
 301
 302        rtc->regs = devm_platform_ioremap_resource(op, 0);
 303        if (IS_ERR(rtc->regs)) {
 304                dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
 305                return PTR_ERR(rtc->regs);
 306        }
 307
 308        device_init_wakeup(&op->dev, 1);
 309
 310        platform_set_drvdata(op, rtc);
 311
 312        rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
 313        err = devm_request_irq(&op->dev, rtc->irq, mpc5121_rtc_handler, 0,
 314                               "mpc5121-rtc", &op->dev);
 315        if (err) {
 316                dev_err(&op->dev, "%s: could not request irq: %i\n",
 317                                                        __func__, rtc->irq);
 318                goto out_dispose;
 319        }
 320
 321        rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0);
 322        err = devm_request_irq(&op->dev, rtc->irq_periodic,
 323                               mpc5121_rtc_handler_upd, 0, "mpc5121-rtc_upd",
 324                               &op->dev);
 325        if (err) {
 326                dev_err(&op->dev, "%s: could not request irq: %i\n",
 327                                                __func__, rtc->irq_periodic);
 328                goto out_dispose2;
 329        }
 330
 331        rtc->rtc = devm_rtc_allocate_device(&op->dev);
 332        if (IS_ERR(rtc->rtc)) {
 333                err = PTR_ERR(rtc->rtc);
 334                goto out_dispose2;
 335        }
 336
 337        rtc->rtc->ops = &mpc5200_rtc_ops;
 338        set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtc->features);
 339        clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtc->features);
 340        rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_0000;
 341        rtc->rtc->range_max = 65733206399ULL; /* 4052-12-31 23:59:59 */
 342
 343        if (of_device_is_compatible(op->dev.of_node, "fsl,mpc5121-rtc")) {
 344                u32 ka;
 345                ka = in_be32(&rtc->regs->keep_alive);
 346                if (ka & 0x02) {
 347                        dev_warn(&op->dev,
 348                                "mpc5121-rtc: Battery or oscillator failure!\n");
 349                        out_be32(&rtc->regs->keep_alive, ka);
 350                }
 351                rtc->rtc->ops = &mpc5121_rtc_ops;
 352                /*
 353                 * This is a limitation of the driver that abuses the target
 354                 * time register, the actual maximum year for the mpc5121 is
 355                 * also 4052.
 356                 */
 357                rtc->rtc->range_min = 0;
 358                rtc->rtc->range_max = U32_MAX;
 359        }
 360
 361        err = devm_rtc_register_device(rtc->rtc);
 362        if (err)
 363                goto out_dispose2;
 364
 365        return 0;
 366
 367out_dispose2:
 368        irq_dispose_mapping(rtc->irq_periodic);
 369out_dispose:
 370        irq_dispose_mapping(rtc->irq);
 371
 372        return err;
 373}
 374
 375static int mpc5121_rtc_remove(struct platform_device *op)
 376{
 377        struct mpc5121_rtc_data *rtc = platform_get_drvdata(op);
 378        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 379
 380        /* disable interrupt, so there are no nasty surprises */
 381        out_8(&regs->alm_enable, 0);
 382        out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
 383
 384        irq_dispose_mapping(rtc->irq);
 385        irq_dispose_mapping(rtc->irq_periodic);
 386
 387        return 0;
 388}
 389
 390#ifdef CONFIG_OF
 391static const struct of_device_id mpc5121_rtc_match[] = {
 392        { .compatible = "fsl,mpc5121-rtc", },
 393        { .compatible = "fsl,mpc5200-rtc", },
 394        {},
 395};
 396MODULE_DEVICE_TABLE(of, mpc5121_rtc_match);
 397#endif
 398
 399static struct platform_driver mpc5121_rtc_driver = {
 400        .driver = {
 401                .name = "mpc5121-rtc",
 402                .of_match_table = of_match_ptr(mpc5121_rtc_match),
 403        },
 404        .probe = mpc5121_rtc_probe,
 405        .remove = mpc5121_rtc_remove,
 406};
 407
 408module_platform_driver(mpc5121_rtc_driver);
 409
 410MODULE_LICENSE("GPL");
 411MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");
 412