linux/drivers/rtc/rtc-pcf50633.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* NXP PCF50633 RTC Driver
   3 *
   4 * (C) 2006-2008 by Openmoko, Inc.
   5 * Author: Balaji Rao <balajirrao@openmoko.org>
   6 * All rights reserved.
   7 *
   8 * Broken down from monstrous PCF50633 driver mainly by
   9 * Harald Welte, Andy Green and Werner Almesberger
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/init.h>
  15#include <linux/device.h>
  16#include <linux/slab.h>
  17#include <linux/platform_device.h>
  18#include <linux/rtc.h>
  19#include <linux/bcd.h>
  20#include <linux/err.h>
  21
  22#include <linux/mfd/pcf50633/core.h>
  23
  24#define PCF50633_REG_RTCSC      0x59 /* Second */
  25#define PCF50633_REG_RTCMN      0x5a /* Minute */
  26#define PCF50633_REG_RTCHR      0x5b /* Hour */
  27#define PCF50633_REG_RTCWD      0x5c /* Weekday */
  28#define PCF50633_REG_RTCDT      0x5d /* Day */
  29#define PCF50633_REG_RTCMT      0x5e /* Month */
  30#define PCF50633_REG_RTCYR      0x5f /* Year */
  31#define PCF50633_REG_RTCSCA     0x60 /* Alarm Second */
  32#define PCF50633_REG_RTCMNA     0x61 /* Alarm Minute */
  33#define PCF50633_REG_RTCHRA     0x62 /* Alarm Hour */
  34#define PCF50633_REG_RTCWDA     0x63 /* Alarm Weekday */
  35#define PCF50633_REG_RTCDTA     0x64 /* Alarm Day */
  36#define PCF50633_REG_RTCMTA     0x65 /* Alarm Month */
  37#define PCF50633_REG_RTCYRA     0x66 /* Alarm Year */
  38
  39enum pcf50633_time_indexes {
  40        PCF50633_TI_SEC,
  41        PCF50633_TI_MIN,
  42        PCF50633_TI_HOUR,
  43        PCF50633_TI_WKDAY,
  44        PCF50633_TI_DAY,
  45        PCF50633_TI_MONTH,
  46        PCF50633_TI_YEAR,
  47        PCF50633_TI_EXTENT /* always last */
  48};
  49
  50struct pcf50633_time {
  51        u_int8_t time[PCF50633_TI_EXTENT];
  52};
  53
  54struct pcf50633_rtc {
  55        int alarm_enabled;
  56        int alarm_pending;
  57
  58        struct pcf50633 *pcf;
  59        struct rtc_device *rtc_dev;
  60};
  61
  62static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf)
  63{
  64        rtc->tm_sec = bcd2bin(pcf->time[PCF50633_TI_SEC]);
  65        rtc->tm_min = bcd2bin(pcf->time[PCF50633_TI_MIN]);
  66        rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]);
  67        rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]);
  68        rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]);
  69        rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]) - 1;
  70        rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100;
  71}
  72
  73static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc)
  74{
  75        pcf->time[PCF50633_TI_SEC] = bin2bcd(rtc->tm_sec);
  76        pcf->time[PCF50633_TI_MIN] = bin2bcd(rtc->tm_min);
  77        pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour);
  78        pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday);
  79        pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday);
  80        pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon + 1);
  81        pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100);
  82}
  83
  84static int
  85pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
  86{
  87        struct pcf50633_rtc *rtc = dev_get_drvdata(dev);
  88        int err;
  89
  90        if (enabled)
  91                err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
  92        else
  93                err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
  94
  95        if (err < 0)
  96                return err;
  97
  98        rtc->alarm_enabled = enabled;
  99
 100        return 0;
 101}
 102
 103static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm)
 104{
 105        struct pcf50633_rtc *rtc;
 106        struct pcf50633_time pcf_tm;
 107        int ret;
 108
 109        rtc = dev_get_drvdata(dev);
 110
 111        ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC,
 112                                            PCF50633_TI_EXTENT,
 113                                            &pcf_tm.time[0]);
 114        if (ret != PCF50633_TI_EXTENT) {
 115                dev_err(dev, "Failed to read time\n");
 116                return -EIO;
 117        }
 118
 119        dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
 120                pcf_tm.time[PCF50633_TI_DAY],
 121                pcf_tm.time[PCF50633_TI_MONTH],
 122                pcf_tm.time[PCF50633_TI_YEAR],
 123                pcf_tm.time[PCF50633_TI_HOUR],
 124                pcf_tm.time[PCF50633_TI_MIN],
 125                pcf_tm.time[PCF50633_TI_SEC]);
 126
 127        pcf2rtc_time(tm, &pcf_tm);
 128
 129        dev_dbg(dev, "RTC_TIME: %ptRr\n", tm);
 130
 131        return 0;
 132}
 133
 134static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
 135{
 136        struct pcf50633_rtc *rtc;
 137        struct pcf50633_time pcf_tm;
 138        int alarm_masked, ret = 0;
 139
 140        rtc = dev_get_drvdata(dev);
 141
 142        dev_dbg(dev, "RTC_TIME: %ptRr\n", tm);
 143
 144        rtc2pcf_time(&pcf_tm, tm);
 145
 146        dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
 147                pcf_tm.time[PCF50633_TI_DAY],
 148                pcf_tm.time[PCF50633_TI_MONTH],
 149                pcf_tm.time[PCF50633_TI_YEAR],
 150                pcf_tm.time[PCF50633_TI_HOUR],
 151                pcf_tm.time[PCF50633_TI_MIN],
 152                pcf_tm.time[PCF50633_TI_SEC]);
 153
 154
 155        alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
 156
 157        if (!alarm_masked)
 158                pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
 159
 160        /* Returns 0 on success */
 161        ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSC,
 162                                             PCF50633_TI_EXTENT,
 163                                             &pcf_tm.time[0]);
 164
 165        if (!alarm_masked)
 166                pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
 167
 168        return ret;
 169}
 170
 171static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 172{
 173        struct pcf50633_rtc *rtc;
 174        struct pcf50633_time pcf_tm;
 175        int ret = 0;
 176
 177        rtc = dev_get_drvdata(dev);
 178
 179        alrm->enabled = rtc->alarm_enabled;
 180        alrm->pending = rtc->alarm_pending;
 181
 182        ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA,
 183                                PCF50633_TI_EXTENT, &pcf_tm.time[0]);
 184        if (ret != PCF50633_TI_EXTENT) {
 185                dev_err(dev, "Failed to read time\n");
 186                return -EIO;
 187        }
 188
 189        pcf2rtc_time(&alrm->time, &pcf_tm);
 190
 191        return rtc_valid_tm(&alrm->time);
 192}
 193
 194static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 195{
 196        struct pcf50633_rtc *rtc;
 197        struct pcf50633_time pcf_tm;
 198        int alarm_masked, ret = 0;
 199
 200        rtc = dev_get_drvdata(dev);
 201
 202        rtc2pcf_time(&pcf_tm, &alrm->time);
 203
 204        /* do like mktime does and ignore tm_wday */
 205        pcf_tm.time[PCF50633_TI_WKDAY] = 7;
 206
 207        alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
 208
 209        /* disable alarm interrupt */
 210        if (!alarm_masked)
 211                pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
 212
 213        /* Returns 0 on success */
 214        ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA,
 215                                PCF50633_TI_EXTENT, &pcf_tm.time[0]);
 216        if (!alrm->enabled)
 217                rtc->alarm_pending = 0;
 218
 219        if (!alarm_masked || alrm->enabled)
 220                pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
 221        rtc->alarm_enabled = alrm->enabled;
 222
 223        return ret;
 224}
 225
 226static const struct rtc_class_ops pcf50633_rtc_ops = {
 227        .read_time              = pcf50633_rtc_read_time,
 228        .set_time               = pcf50633_rtc_set_time,
 229        .read_alarm             = pcf50633_rtc_read_alarm,
 230        .set_alarm              = pcf50633_rtc_set_alarm,
 231        .alarm_irq_enable       = pcf50633_rtc_alarm_irq_enable,
 232};
 233
 234static void pcf50633_rtc_irq(int irq, void *data)
 235{
 236        struct pcf50633_rtc *rtc = data;
 237
 238        rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
 239        rtc->alarm_pending = 1;
 240}
 241
 242static int pcf50633_rtc_probe(struct platform_device *pdev)
 243{
 244        struct pcf50633_rtc *rtc;
 245
 246        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
 247        if (!rtc)
 248                return -ENOMEM;
 249
 250        rtc->pcf = dev_to_pcf50633(pdev->dev.parent);
 251        platform_set_drvdata(pdev, rtc);
 252        rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, "pcf50633-rtc",
 253                                &pcf50633_rtc_ops, THIS_MODULE);
 254
 255        if (IS_ERR(rtc->rtc_dev))
 256                return PTR_ERR(rtc->rtc_dev);
 257
 258        pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM,
 259                                        pcf50633_rtc_irq, rtc);
 260        return 0;
 261}
 262
 263static int pcf50633_rtc_remove(struct platform_device *pdev)
 264{
 265        struct pcf50633_rtc *rtc;
 266
 267        rtc = platform_get_drvdata(pdev);
 268        pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM);
 269
 270        return 0;
 271}
 272
 273static struct platform_driver pcf50633_rtc_driver = {
 274        .driver = {
 275                .name = "pcf50633-rtc",
 276        },
 277        .probe = pcf50633_rtc_probe,
 278        .remove = pcf50633_rtc_remove,
 279};
 280
 281module_platform_driver(pcf50633_rtc_driver);
 282
 283MODULE_DESCRIPTION("PCF50633 RTC driver");
 284MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
 285MODULE_LICENSE("GPL");
 286
 287