linux/drivers/rtc/rtc-max8925.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * RTC driver for Maxim MAX8925
   4 *
   5 * Copyright (C) 2009-2010 Marvell International Ltd.
   6 *      Haojian Zhuang <haojian.zhuang@marvell.com>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/i2c.h>
  11#include <linux/slab.h>
  12#include <linux/rtc.h>
  13#include <linux/platform_device.h>
  14#include <linux/mfd/max8925.h>
  15
  16enum {
  17        RTC_SEC = 0,
  18        RTC_MIN,
  19        RTC_HOUR,
  20        RTC_WEEKDAY,
  21        RTC_DATE,
  22        RTC_MONTH,
  23        RTC_YEAR1,
  24        RTC_YEAR2,
  25};
  26
  27#define MAX8925_RTC_SEC                 0x00
  28#define MAX8925_RTC_MIN                 0x01
  29#define MAX8925_RTC_HOUR                0x02
  30#define MAX8925_RTC_WEEKDAY             0x03
  31#define MAX8925_RTC_DATE                0x04
  32#define MAX8925_RTC_MONTH               0x05
  33#define MAX8925_RTC_YEAR1               0x06
  34#define MAX8925_RTC_YEAR2               0x07
  35#define MAX8925_ALARM0_SEC              0x08
  36#define MAX8925_ALARM0_MIN              0x09
  37#define MAX8925_ALARM0_HOUR             0x0a
  38#define MAX8925_ALARM0_WEEKDAY          0x0b
  39#define MAX8925_ALARM0_DATE             0x0c
  40#define MAX8925_ALARM0_MON              0x0d
  41#define MAX8925_ALARM0_YEAR1            0x0e
  42#define MAX8925_ALARM0_YEAR2            0x0f
  43#define MAX8925_ALARM1_SEC              0x10
  44#define MAX8925_ALARM1_MIN              0x11
  45#define MAX8925_ALARM1_HOUR             0x12
  46#define MAX8925_ALARM1_WEEKDAY          0x13
  47#define MAX8925_ALARM1_DATE             0x14
  48#define MAX8925_ALARM1_MON              0x15
  49#define MAX8925_ALARM1_YEAR1            0x16
  50#define MAX8925_ALARM1_YEAR2            0x17
  51#define MAX8925_RTC_CNTL                0x1b
  52#define MAX8925_RTC_STATUS              0x20
  53
  54#define TIME_NUM                        8
  55#define ALARM_1SEC                      (1 << 7)
  56#define HOUR_12                         (1 << 7)
  57#define HOUR_AM_PM                      (1 << 5)
  58#define ALARM0_IRQ                      (1 << 3)
  59#define ALARM1_IRQ                      (1 << 2)
  60#define ALARM0_STATUS                   (1 << 2)
  61#define ALARM1_STATUS                   (1 << 1)
  62
  63
  64struct max8925_rtc_info {
  65        struct rtc_device       *rtc_dev;
  66        struct max8925_chip     *chip;
  67        struct i2c_client       *rtc;
  68        struct device           *dev;
  69        int                     irq;
  70};
  71
  72static irqreturn_t rtc_update_handler(int irq, void *data)
  73{
  74        struct max8925_rtc_info *info = (struct max8925_rtc_info *)data;
  75
  76        /* disable ALARM0 except for 1SEC alarm */
  77        max8925_set_bits(info->rtc, MAX8925_ALARM0_CNTL, 0x7f, 0);
  78        rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
  79        return IRQ_HANDLED;
  80}
  81
  82static int tm_calc(struct rtc_time *tm, unsigned char *buf, int len)
  83{
  84        if (len < TIME_NUM)
  85                return -EINVAL;
  86        tm->tm_year = (buf[RTC_YEAR2] >> 4) * 1000
  87                        + (buf[RTC_YEAR2] & 0xf) * 100
  88                        + (buf[RTC_YEAR1] >> 4) * 10
  89                        + (buf[RTC_YEAR1] & 0xf);
  90        tm->tm_year -= 1900;
  91        tm->tm_mon = ((buf[RTC_MONTH] >> 4) & 0x01) * 10
  92                        + (buf[RTC_MONTH] & 0x0f);
  93        tm->tm_mday = ((buf[RTC_DATE] >> 4) & 0x03) * 10
  94                        + (buf[RTC_DATE] & 0x0f);
  95        tm->tm_wday = buf[RTC_WEEKDAY] & 0x07;
  96        if (buf[RTC_HOUR] & HOUR_12) {
  97                tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x1) * 10
  98                                + (buf[RTC_HOUR] & 0x0f);
  99                if (buf[RTC_HOUR] & HOUR_AM_PM)
 100                        tm->tm_hour += 12;
 101        } else
 102                tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x03) * 10
 103                                + (buf[RTC_HOUR] & 0x0f);
 104        tm->tm_min = ((buf[RTC_MIN] >> 4) & 0x7) * 10
 105                        + (buf[RTC_MIN] & 0x0f);
 106        tm->tm_sec = ((buf[RTC_SEC] >> 4) & 0x7) * 10
 107                        + (buf[RTC_SEC] & 0x0f);
 108        return 0;
 109}
 110
 111static int data_calc(unsigned char *buf, struct rtc_time *tm, int len)
 112{
 113        unsigned char high, low;
 114
 115        if (len < TIME_NUM)
 116                return -EINVAL;
 117
 118        high = (tm->tm_year + 1900) / 1000;
 119        low = (tm->tm_year + 1900) / 100;
 120        low = low - high * 10;
 121        buf[RTC_YEAR2] = (high << 4) + low;
 122        high = (tm->tm_year + 1900) / 10;
 123        low = tm->tm_year + 1900;
 124        low = low - high * 10;
 125        high = high - (high / 10) * 10;
 126        buf[RTC_YEAR1] = (high << 4) + low;
 127        high = tm->tm_mon / 10;
 128        low = tm->tm_mon;
 129        low = low - high * 10;
 130        buf[RTC_MONTH] = (high << 4) + low;
 131        high = tm->tm_mday / 10;
 132        low = tm->tm_mday;
 133        low = low - high * 10;
 134        buf[RTC_DATE] = (high << 4) + low;
 135        buf[RTC_WEEKDAY] = tm->tm_wday;
 136        high = tm->tm_hour / 10;
 137        low = tm->tm_hour;
 138        low = low - high * 10;
 139        buf[RTC_HOUR] = (high << 4) + low;
 140        high = tm->tm_min / 10;
 141        low = tm->tm_min;
 142        low = low - high * 10;
 143        buf[RTC_MIN] = (high << 4) + low;
 144        high = tm->tm_sec / 10;
 145        low = tm->tm_sec;
 146        low = low - high * 10;
 147        buf[RTC_SEC] = (high << 4) + low;
 148        return 0;
 149}
 150
 151static int max8925_rtc_read_time(struct device *dev, struct rtc_time *tm)
 152{
 153        struct max8925_rtc_info *info = dev_get_drvdata(dev);
 154        unsigned char buf[TIME_NUM];
 155        int ret;
 156
 157        ret = max8925_bulk_read(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf);
 158        if (ret < 0)
 159                goto out;
 160        ret = tm_calc(tm, buf, TIME_NUM);
 161out:
 162        return ret;
 163}
 164
 165static int max8925_rtc_set_time(struct device *dev, struct rtc_time *tm)
 166{
 167        struct max8925_rtc_info *info = dev_get_drvdata(dev);
 168        unsigned char buf[TIME_NUM];
 169        int ret;
 170
 171        ret = data_calc(buf, tm, TIME_NUM);
 172        if (ret < 0)
 173                goto out;
 174        ret = max8925_bulk_write(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf);
 175out:
 176        return ret;
 177}
 178
 179static int max8925_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 180{
 181        struct max8925_rtc_info *info = dev_get_drvdata(dev);
 182        unsigned char buf[TIME_NUM];
 183        int ret;
 184
 185        ret = max8925_bulk_read(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf);
 186        if (ret < 0)
 187                goto out;
 188        ret = tm_calc(&alrm->time, buf, TIME_NUM);
 189        if (ret < 0)
 190                goto out;
 191        ret = max8925_reg_read(info->rtc, MAX8925_RTC_IRQ_MASK);
 192        if (ret < 0)
 193                goto out;
 194        if (ret & ALARM0_IRQ) {
 195                alrm->enabled = 0;
 196        } else {
 197                ret = max8925_reg_read(info->rtc, MAX8925_ALARM0_CNTL);
 198                if (ret < 0)
 199                        goto out;
 200                if (!ret)
 201                        alrm->enabled = 0;
 202                else
 203                        alrm->enabled = 1;
 204        }
 205        ret = max8925_reg_read(info->rtc, MAX8925_RTC_STATUS);
 206        if (ret < 0)
 207                goto out;
 208        if (ret & ALARM0_STATUS)
 209                alrm->pending = 1;
 210        else
 211                alrm->pending = 0;
 212        return 0;
 213out:
 214        return ret;
 215}
 216
 217static int max8925_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 218{
 219        struct max8925_rtc_info *info = dev_get_drvdata(dev);
 220        unsigned char buf[TIME_NUM];
 221        int ret;
 222
 223        ret = data_calc(buf, &alrm->time, TIME_NUM);
 224        if (ret < 0)
 225                goto out;
 226        ret = max8925_bulk_write(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf);
 227        if (ret < 0)
 228                goto out;
 229        if (alrm->enabled)
 230                /* only enable alarm on year/month/day/hour/min/sec */
 231                ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77);
 232        else
 233                ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x0);
 234out:
 235        return ret;
 236}
 237
 238static const struct rtc_class_ops max8925_rtc_ops = {
 239        .read_time      = max8925_rtc_read_time,
 240        .set_time       = max8925_rtc_set_time,
 241        .read_alarm     = max8925_rtc_read_alarm,
 242        .set_alarm      = max8925_rtc_set_alarm,
 243};
 244
 245static int max8925_rtc_probe(struct platform_device *pdev)
 246{
 247        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 248        struct max8925_rtc_info *info;
 249        int ret;
 250
 251        info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_rtc_info),
 252                            GFP_KERNEL);
 253        if (!info)
 254                return -ENOMEM;
 255        info->chip = chip;
 256        info->rtc = chip->rtc;
 257        info->dev = &pdev->dev;
 258        info->irq = platform_get_irq(pdev, 0);
 259
 260        ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
 261                                        rtc_update_handler, IRQF_ONESHOT,
 262                                        "rtc-alarm0", info);
 263        if (ret < 0) {
 264                dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
 265                        info->irq, ret);
 266                return ret;
 267        }
 268
 269        dev_set_drvdata(&pdev->dev, info);
 270        /* XXX - isn't this redundant? */
 271        platform_set_drvdata(pdev, info);
 272
 273        device_init_wakeup(&pdev->dev, 1);
 274
 275        info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max8925-rtc",
 276                                        &max8925_rtc_ops, THIS_MODULE);
 277        ret = PTR_ERR(info->rtc_dev);
 278        if (IS_ERR(info->rtc_dev)) {
 279                dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
 280                return ret;
 281        }
 282
 283        return 0;
 284}
 285
 286#ifdef CONFIG_PM_SLEEP
 287static int max8925_rtc_suspend(struct device *dev)
 288{
 289        struct platform_device *pdev = to_platform_device(dev);
 290        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 291
 292        if (device_may_wakeup(dev))
 293                chip->wakeup_flag |= 1 << MAX8925_IRQ_RTC_ALARM0;
 294        return 0;
 295}
 296static int max8925_rtc_resume(struct device *dev)
 297{
 298        struct platform_device *pdev = to_platform_device(dev);
 299        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 300
 301        if (device_may_wakeup(dev))
 302                chip->wakeup_flag &= ~(1 << MAX8925_IRQ_RTC_ALARM0);
 303        return 0;
 304}
 305#endif
 306
 307static SIMPLE_DEV_PM_OPS(max8925_rtc_pm_ops, max8925_rtc_suspend, max8925_rtc_resume);
 308
 309static struct platform_driver max8925_rtc_driver = {
 310        .driver         = {
 311                .name   = "max8925-rtc",
 312                .pm     = &max8925_rtc_pm_ops,
 313        },
 314        .probe          = max8925_rtc_probe,
 315};
 316
 317module_platform_driver(max8925_rtc_driver);
 318
 319MODULE_DESCRIPTION("Maxim MAX8925 RTC driver");
 320MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
 321MODULE_LICENSE("GPL");
 322
 323