root/drivers/rtc/rtc-max8925.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rtc_update_handler
  2. tm_calc
  3. data_calc
  4. max8925_rtc_read_time
  5. max8925_rtc_set_time
  6. max8925_rtc_read_alarm
  7. max8925_rtc_set_alarm
  8. max8925_rtc_probe
  9. max8925_rtc_suspend
  10. max8925_rtc_resume

   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 
  16 enum {
  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 
  64 struct 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 
  72 static 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 
  82 static 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 
 111 static 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 
 151 static 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);
 161 out:
 162         return ret;
 163 }
 164 
 165 static 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);
 175 out:
 176         return ret;
 177 }
 178 
 179 static 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;
 213 out:
 214         return ret;
 215 }
 216 
 217 static 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);
 234 out:
 235         return ret;
 236 }
 237 
 238 static 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 
 245 static 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
 287 static 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 }
 296 static 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 
 307 static SIMPLE_DEV_PM_OPS(max8925_rtc_pm_ops, max8925_rtc_suspend, max8925_rtc_resume);
 308 
 309 static 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 
 317 module_platform_driver(max8925_rtc_driver);
 318 
 319 MODULE_DESCRIPTION("Maxim MAX8925 RTC driver");
 320 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
 321 MODULE_LICENSE("GPL");
 322 

/* [<][>][^][v][top][bottom][index][help] */