linux/drivers/rtc/rtc-mc13xxx.c
<<
>>
Prefs
   1/*
   2 * Real Time Clock driver for Freescale MC13XXX PMIC
   3 *
   4 * (C) 2009 Sascha Hauer, Pengutronix
   5 * (C) 2009 Uwe Kleine-Koenig, Pengutronix
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/mfd/mc13xxx.h>
  13#include <linux/platform_device.h>
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/slab.h>
  17#include <linux/rtc.h>
  18
  19#define DRIVER_NAME "mc13xxx-rtc"
  20
  21#define MC13XXX_RTCTOD  20
  22#define MC13XXX_RTCTODA 21
  23#define MC13XXX_RTCDAY  22
  24#define MC13XXX_RTCDAYA 23
  25
  26struct mc13xxx_rtc {
  27        struct rtc_device *rtc;
  28        struct mc13xxx *mc13xxx;
  29        int valid;
  30};
  31
  32static int mc13xxx_rtc_irq_enable_unlocked(struct device *dev,
  33                unsigned int enabled, int irq)
  34{
  35        struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
  36        int (*func)(struct mc13xxx *mc13xxx, int irq);
  37
  38        if (!priv->valid)
  39                return -ENODATA;
  40
  41        func = enabled ? mc13xxx_irq_unmask : mc13xxx_irq_mask;
  42        return func(priv->mc13xxx, irq);
  43}
  44
  45static int mc13xxx_rtc_irq_enable(struct device *dev,
  46                unsigned int enabled, int irq)
  47{
  48        struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
  49        int ret;
  50
  51        mc13xxx_lock(priv->mc13xxx);
  52
  53        ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, irq);
  54
  55        mc13xxx_unlock(priv->mc13xxx);
  56
  57        return ret;
  58}
  59
  60static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
  61{
  62        struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
  63        unsigned int seconds, days1, days2;
  64        unsigned long s1970;
  65        int ret;
  66
  67        mc13xxx_lock(priv->mc13xxx);
  68
  69        if (!priv->valid) {
  70                ret = -ENODATA;
  71                goto out;
  72        }
  73
  74        ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1);
  75        if (unlikely(ret))
  76                goto out;
  77
  78        ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds);
  79        if (unlikely(ret))
  80                goto out;
  81
  82        ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2);
  83out:
  84        mc13xxx_unlock(priv->mc13xxx);
  85
  86        if (ret)
  87                return ret;
  88
  89        if (days2 == days1 + 1) {
  90                if (seconds >= 86400 / 2)
  91                        days2 = days1;
  92                else
  93                        days1 = days2;
  94        }
  95
  96        if (days1 != days2)
  97                return -EIO;
  98
  99        s1970 = days1 * 86400 + seconds;
 100
 101        rtc_time_to_tm(s1970, tm);
 102
 103        return rtc_valid_tm(tm);
 104}
 105
 106static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)
 107{
 108        struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
 109        unsigned int seconds, days;
 110        unsigned int alarmseconds;
 111        int ret;
 112
 113        seconds = secs % 86400;
 114        days = secs / 86400;
 115
 116        mc13xxx_lock(priv->mc13xxx);
 117
 118        /*
 119         * temporarily invalidate alarm to prevent triggering it when the day is
 120         * already updated while the time isn't yet.
 121         */
 122        ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &alarmseconds);
 123        if (unlikely(ret))
 124                goto out;
 125
 126        if (alarmseconds < 86400) {
 127                ret = mc13xxx_reg_write(priv->mc13xxx,
 128                                MC13XXX_RTCTODA, 0x1ffff);
 129                if (unlikely(ret))
 130                        goto out;
 131        }
 132
 133        /*
 134         * write seconds=0 to prevent a day switch between writing days
 135         * and seconds below
 136         */
 137        ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, 0);
 138        if (unlikely(ret))
 139                goto out;
 140
 141        ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAY, days);
 142        if (unlikely(ret))
 143                goto out;
 144
 145        ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, seconds);
 146        if (unlikely(ret))
 147                goto out;
 148
 149        /* restore alarm */
 150        if (alarmseconds < 86400) {
 151                ret = mc13xxx_reg_write(priv->mc13xxx,
 152                                MC13XXX_RTCTODA, alarmseconds);
 153                if (unlikely(ret))
 154                        goto out;
 155        }
 156
 157        ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
 158        if (unlikely(ret))
 159                goto out;
 160
 161        ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
 162out:
 163        priv->valid = !ret;
 164
 165        mc13xxx_unlock(priv->mc13xxx);
 166
 167        return ret;
 168}
 169
 170static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 171{
 172        struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
 173        unsigned seconds, days;
 174        unsigned long s1970;
 175        int enabled, pending;
 176        int ret;
 177
 178        mc13xxx_lock(priv->mc13xxx);
 179
 180        ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds);
 181        if (unlikely(ret))
 182                goto out;
 183        if (seconds >= 86400) {
 184                ret = -ENODATA;
 185                goto out;
 186        }
 187
 188        ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days);
 189        if (unlikely(ret))
 190                goto out;
 191
 192        ret = mc13xxx_irq_status(priv->mc13xxx, MC13XXX_IRQ_TODA,
 193                        &enabled, &pending);
 194
 195out:
 196        mc13xxx_unlock(priv->mc13xxx);
 197
 198        if (ret)
 199                return ret;
 200
 201        alarm->enabled = enabled;
 202        alarm->pending = pending;
 203
 204        s1970 = days * 86400 + seconds;
 205
 206        rtc_time_to_tm(s1970, &alarm->time);
 207        dev_dbg(dev, "%s: %lu\n", __func__, s1970);
 208
 209        return 0;
 210}
 211
 212static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 213{
 214        struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
 215        unsigned long s1970;
 216        unsigned seconds, days;
 217        int ret;
 218
 219        mc13xxx_lock(priv->mc13xxx);
 220
 221        /* disable alarm to prevent false triggering */
 222        ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, 0x1ffff);
 223        if (unlikely(ret))
 224                goto out;
 225
 226        ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TODA);
 227        if (unlikely(ret))
 228                goto out;
 229
 230        ret = rtc_tm_to_time(&alarm->time, &s1970);
 231        if (unlikely(ret))
 232                goto out;
 233
 234        dev_dbg(dev, "%s: o%2.s %lu\n", __func__, alarm->enabled ? "n" : "ff",
 235                        s1970);
 236
 237        ret = mc13xxx_rtc_irq_enable_unlocked(dev, alarm->enabled,
 238                        MC13XXX_IRQ_TODA);
 239        if (unlikely(ret))
 240                goto out;
 241
 242        seconds = s1970 % 86400;
 243        days = s1970 / 86400;
 244
 245        ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days);
 246        if (unlikely(ret))
 247                goto out;
 248
 249        ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, seconds);
 250
 251out:
 252        mc13xxx_unlock(priv->mc13xxx);
 253
 254        return ret;
 255}
 256
 257static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev)
 258{
 259        struct mc13xxx_rtc *priv = dev;
 260        struct mc13xxx *mc13xxx = priv->mc13xxx;
 261
 262        dev_dbg(&priv->rtc->dev, "Alarm\n");
 263
 264        rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
 265
 266        mc13xxx_irq_ack(mc13xxx, irq);
 267
 268        return IRQ_HANDLED;
 269}
 270
 271static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)
 272{
 273        struct mc13xxx_rtc *priv = dev;
 274        struct mc13xxx *mc13xxx = priv->mc13xxx;
 275
 276        dev_dbg(&priv->rtc->dev, "1HZ\n");
 277
 278        rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
 279
 280        mc13xxx_irq_ack(mc13xxx, irq);
 281
 282        return IRQ_HANDLED;
 283}
 284
 285static int mc13xxx_rtc_alarm_irq_enable(struct device *dev,
 286                unsigned int enabled)
 287{
 288        return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_TODA);
 289}
 290
 291static const struct rtc_class_ops mc13xxx_rtc_ops = {
 292        .read_time = mc13xxx_rtc_read_time,
 293        .set_mmss = mc13xxx_rtc_set_mmss,
 294        .read_alarm = mc13xxx_rtc_read_alarm,
 295        .set_alarm = mc13xxx_rtc_set_alarm,
 296        .alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable,
 297};
 298
 299static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev)
 300{
 301        struct mc13xxx_rtc *priv = dev;
 302        struct mc13xxx *mc13xxx = priv->mc13xxx;
 303
 304        dev_dbg(&priv->rtc->dev, "RTCRST\n");
 305        priv->valid = 0;
 306
 307        mc13xxx_irq_mask(mc13xxx, irq);
 308
 309        return IRQ_HANDLED;
 310}
 311
 312static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
 313{
 314        int ret;
 315        struct mc13xxx_rtc *priv;
 316        struct mc13xxx *mc13xxx;
 317        int rtcrst_pending;
 318
 319        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 320        if (!priv)
 321                return -ENOMEM;
 322
 323        mc13xxx = dev_get_drvdata(pdev->dev.parent);
 324        priv->mc13xxx = mc13xxx;
 325
 326        platform_set_drvdata(pdev, priv);
 327
 328        mc13xxx_lock(mc13xxx);
 329
 330        ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST,
 331                        mc13xxx_rtc_reset_handler, DRIVER_NAME, priv);
 332        if (ret)
 333                goto err_reset_irq_request;
 334
 335        ret = mc13xxx_irq_status(mc13xxx, MC13XXX_IRQ_RTCRST,
 336                        NULL, &rtcrst_pending);
 337        if (ret)
 338                goto err_reset_irq_status;
 339
 340        priv->valid = !rtcrst_pending;
 341
 342        ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_1HZ,
 343                        mc13xxx_rtc_update_handler, DRIVER_NAME, priv);
 344        if (ret)
 345                goto err_update_irq_request;
 346
 347        ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA,
 348                        mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv);
 349        if (ret)
 350                goto err_alarm_irq_request;
 351
 352        mc13xxx_unlock(mc13xxx);
 353
 354        priv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
 355                                        &mc13xxx_rtc_ops, THIS_MODULE);
 356        if (IS_ERR(priv->rtc)) {
 357                ret = PTR_ERR(priv->rtc);
 358
 359                mc13xxx_lock(mc13xxx);
 360
 361                mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv);
 362err_alarm_irq_request:
 363
 364                mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv);
 365err_update_irq_request:
 366
 367err_reset_irq_status:
 368
 369                mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv);
 370err_reset_irq_request:
 371
 372                mc13xxx_unlock(mc13xxx);
 373        }
 374
 375        return ret;
 376}
 377
 378static int __exit mc13xxx_rtc_remove(struct platform_device *pdev)
 379{
 380        struct mc13xxx_rtc *priv = platform_get_drvdata(pdev);
 381
 382        mc13xxx_lock(priv->mc13xxx);
 383
 384        mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TODA, priv);
 385        mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_1HZ, priv);
 386        mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv);
 387
 388        mc13xxx_unlock(priv->mc13xxx);
 389
 390        return 0;
 391}
 392
 393static const struct platform_device_id mc13xxx_rtc_idtable[] = {
 394        {
 395                .name = "mc13783-rtc",
 396        }, {
 397                .name = "mc13892-rtc",
 398        }, {
 399                .name = "mc34708-rtc",
 400        },
 401        { /* sentinel */ }
 402};
 403MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);
 404
 405static struct platform_driver mc13xxx_rtc_driver = {
 406        .id_table = mc13xxx_rtc_idtable,
 407        .remove = __exit_p(mc13xxx_rtc_remove),
 408        .driver = {
 409                .name = DRIVER_NAME,
 410                .owner = THIS_MODULE,
 411        },
 412};
 413
 414module_platform_driver_probe(mc13xxx_rtc_driver, &mc13xxx_rtc_probe);
 415
 416MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 417MODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC");
 418MODULE_LICENSE("GPL v2");
 419
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.