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        /*
 214         * the alarm has no seconds so deal with it
 215         */
 216        if (alarm->time.tm_sec) {
 217                alarm->time.tm_sec = 0;
 218                alarm->time.tm_min++;
 219                if (alarm->time.tm_min >= 60) {
 220                        alarm->time.tm_min = 0;
 221                        alarm->time.tm_hour++;
 222                        if (alarm->time.tm_hour >= 24)
 223                                alarm->time.tm_hour = 0;
 224                }
 225        }
 226
 227        alarm->time.tm_mday = -1;
 228        alarm->time.tm_mon = -1;
 229        alarm->time.tm_year = -1;
 230
 231        out_8(&regs->alm_min_set, alarm->time.tm_min);
 232        out_8(&regs->alm_hour_set, alarm->time.tm_hour);
 233
 234        out_8(&regs->alm_enable, alarm->enabled);
 235
 236        rtc->wkalarm = *alarm;
 237        return 0;
 238}
 239
 240static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
 241{
 242        struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
 243        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 244
 245        if (in_8(&regs->int_alm)) {
 246                /* acknowledge and clear status */
 247                out_8(&regs->int_alm, 1);
 248                out_8(&regs->alm_status, 1);
 249
 250                rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
 251                return IRQ_HANDLED;
 252        }
 253
 254        return IRQ_NONE;
 255}
 256
 257static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
 258{
 259        struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
 260        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 261
 262        if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)) {
 263                /* acknowledge */
 264                out_8(&regs->int_sec, 1);
 265
 266                rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
 267                return IRQ_HANDLED;
 268        }
 269
 270        return IRQ_NONE;
 271}
 272
 273static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
 274                                        unsigned int enabled)
 275{
 276        struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
 277        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 278        int val;
 279
 280        if (enabled)
 281                val = 1;
 282        else
 283                val = 0;
 284
 285        out_8(&regs->alm_enable, val);
 286        rtc->wkalarm.enabled = val;
 287
 288        return 0;
 289}
 290
 291static const struct rtc_class_ops mpc5121_rtc_ops = {
 292        .read_time = mpc5121_rtc_read_time,
 293        .set_time = mpc5121_rtc_set_time,
 294        .read_alarm = mpc5121_rtc_read_alarm,
 295        .set_alarm = mpc5121_rtc_set_alarm,
 296        .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
 297};
 298
 299static const struct rtc_class_ops mpc5200_rtc_ops = {
 300        .read_time = mpc5200_rtc_read_time,
 301        .set_time = mpc5200_rtc_set_time,
 302        .read_alarm = mpc5121_rtc_read_alarm,
 303        .set_alarm = mpc5121_rtc_set_alarm,
 304        .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
 305};
 306
 307static int mpc5121_rtc_probe(struct platform_device *op)
 308{
 309        struct mpc5121_rtc_data *rtc;
 310        int err = 0;
 311
 312        rtc = devm_kzalloc(&op->dev, sizeof(*rtc), GFP_KERNEL);
 313        if (!rtc)
 314                return -ENOMEM;
 315
 316        rtc->regs = devm_platform_ioremap_resource(op, 0);
 317        if (IS_ERR(rtc->regs)) {
 318                dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
 319                return PTR_ERR(rtc->regs);
 320        }
 321
 322        device_init_wakeup(&op->dev, 1);
 323
 324        platform_set_drvdata(op, rtc);
 325
 326        rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
 327        err = devm_request_irq(&op->dev, rtc->irq, mpc5121_rtc_handler, 0,
 328                               "mpc5121-rtc", &op->dev);
 329        if (err) {
 330                dev_err(&op->dev, "%s: could not request irq: %i\n",
 331                                                        __func__, rtc->irq);
 332                goto out_dispose;
 333        }
 334
 335        rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0);
 336        err = devm_request_irq(&op->dev, rtc->irq_periodic,
 337                               mpc5121_rtc_handler_upd, 0, "mpc5121-rtc_upd",
 338                               &op->dev);
 339        if (err) {
 340                dev_err(&op->dev, "%s: could not request irq: %i\n",
 341                                                __func__, rtc->irq_periodic);
 342                goto out_dispose2;
 343        }
 344
 345        rtc->rtc = devm_rtc_allocate_device(&op->dev);
 346        if (IS_ERR(rtc->rtc)) {
 347                err = PTR_ERR(rtc->rtc);
 348                goto out_dispose2;
 349        }
 350
 351        rtc->rtc->ops = &mpc5200_rtc_ops;
 352        rtc->rtc->uie_unsupported = 1;
 353        rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_0000;
 354        rtc->rtc->range_max = 65733206399ULL; /* 4052-12-31 23:59:59 */
 355
 356        if (of_device_is_compatible(op->dev.of_node, "fsl,mpc5121-rtc")) {
 357                u32 ka;
 358                ka = in_be32(&rtc->regs->keep_alive);
 359                if (ka & 0x02) {
 360                        dev_warn(&op->dev,
 361                                "mpc5121-rtc: Battery or oscillator failure!\n");
 362                        out_be32(&rtc->regs->keep_alive, ka);
 363                }
 364                rtc->rtc->ops = &mpc5121_rtc_ops;
 365                /*
 366                 * This is a limitation of the driver that abuses the target
 367                 * time register, the actual maximum year for the mpc5121 is
 368                 * also 4052.
 369                 */
 370                rtc->rtc->range_min = 0;
 371                rtc->rtc->range_max = U32_MAX;
 372        }
 373
 374        err = devm_rtc_register_device(rtc->rtc);
 375        if (err)
 376                goto out_dispose2;
 377
 378        return 0;
 379
 380out_dispose2:
 381        irq_dispose_mapping(rtc->irq_periodic);
 382out_dispose:
 383        irq_dispose_mapping(rtc->irq);
 384
 385        return err;
 386}
 387
 388static int mpc5121_rtc_remove(struct platform_device *op)
 389{
 390        struct mpc5121_rtc_data *rtc = platform_get_drvdata(op);
 391        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 392
 393        /* disable interrupt, so there are no nasty surprises */
 394        out_8(&regs->alm_enable, 0);
 395        out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
 396
 397        irq_dispose_mapping(rtc->irq);
 398        irq_dispose_mapping(rtc->irq_periodic);
 399
 400        return 0;
 401}
 402
 403#ifdef CONFIG_OF
 404static const struct of_device_id mpc5121_rtc_match[] = {
 405        { .compatible = "fsl,mpc5121-rtc", },
 406        { .compatible = "fsl,mpc5200-rtc", },
 407        {},
 408};
 409MODULE_DEVICE_TABLE(of, mpc5121_rtc_match);
 410#endif
 411
 412static struct platform_driver mpc5121_rtc_driver = {
 413        .driver = {
 414                .name = "mpc5121-rtc",
 415                .of_match_table = of_match_ptr(mpc5121_rtc_match),
 416        },
 417        .probe = mpc5121_rtc_probe,
 418        .remove = mpc5121_rtc_remove,
 419};
 420
 421module_platform_driver(mpc5121_rtc_driver);
 422
 423MODULE_LICENSE("GPL");
 424MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");
 425