root/drivers/rtc/rtc-cpcap.c

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

DEFINITIONS

This source file includes following definitions.
  1. cpcap2rtc_time
  2. rtc2cpcap_time
  3. cpcap_rtc_alarm_irq_enable
  4. cpcap_rtc_read_time
  5. cpcap_rtc_set_time
  6. cpcap_rtc_read_alarm
  7. cpcap_rtc_set_alarm
  8. cpcap_rtc_alarm_irq
  9. cpcap_rtc_update_irq
  10. cpcap_rtc_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Motorola CPCAP PMIC RTC driver
   4  *
   5  * Based on cpcap-regulator.c from Motorola Linux kernel tree
   6  * Copyright (C) 2009 Motorola, Inc.
   7  *
   8  * Rewritten for mainline kernel
   9  *  - use DT
  10  *  - use regmap
  11  *  - use standard interrupt framework
  12  *  - use managed device resources
  13  *  - remove custom "secure clock daemon" helpers
  14  *
  15  * Copyright (C) 2017 Sebastian Reichel <sre@kernel.org>
  16  */
  17 #include <linux/kernel.h>
  18 #include <linux/module.h>
  19 #include <linux/mod_devicetable.h>
  20 #include <linux/init.h>
  21 #include <linux/device.h>
  22 #include <linux/platform_device.h>
  23 #include <linux/rtc.h>
  24 #include <linux/err.h>
  25 #include <linux/regmap.h>
  26 #include <linux/mfd/motorola-cpcap.h>
  27 #include <linux/slab.h>
  28 #include <linux/sched.h>
  29 
  30 #define SECS_PER_DAY 86400
  31 #define DAY_MASK  0x7FFF
  32 #define TOD1_MASK 0x00FF
  33 #define TOD2_MASK 0x01FF
  34 
  35 struct cpcap_time {
  36         int day;
  37         int tod1;
  38         int tod2;
  39 };
  40 
  41 struct cpcap_rtc {
  42         struct regmap *regmap;
  43         struct rtc_device *rtc_dev;
  44         u16 vendor;
  45         int alarm_irq;
  46         bool alarm_enabled;
  47         int update_irq;
  48         bool update_enabled;
  49 };
  50 
  51 static void cpcap2rtc_time(struct rtc_time *rtc, struct cpcap_time *cpcap)
  52 {
  53         unsigned long int tod;
  54         unsigned long int time;
  55 
  56         tod = (cpcap->tod1 & TOD1_MASK) | ((cpcap->tod2 & TOD2_MASK) << 8);
  57         time = tod + ((cpcap->day & DAY_MASK) * SECS_PER_DAY);
  58 
  59         rtc_time_to_tm(time, rtc);
  60 }
  61 
  62 static void rtc2cpcap_time(struct cpcap_time *cpcap, struct rtc_time *rtc)
  63 {
  64         unsigned long time;
  65 
  66         rtc_tm_to_time(rtc, &time);
  67 
  68         cpcap->day = time / SECS_PER_DAY;
  69         time %= SECS_PER_DAY;
  70         cpcap->tod2 = (time >> 8) & TOD2_MASK;
  71         cpcap->tod1 = time & TOD1_MASK;
  72 }
  73 
  74 static int cpcap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
  75 {
  76         struct cpcap_rtc *rtc = dev_get_drvdata(dev);
  77 
  78         if (rtc->alarm_enabled == enabled)
  79                 return 0;
  80 
  81         if (enabled)
  82                 enable_irq(rtc->alarm_irq);
  83         else
  84                 disable_irq(rtc->alarm_irq);
  85 
  86         rtc->alarm_enabled = !!enabled;
  87 
  88         return 0;
  89 }
  90 
  91 static int cpcap_rtc_read_time(struct device *dev, struct rtc_time *tm)
  92 {
  93         struct cpcap_rtc *rtc;
  94         struct cpcap_time cpcap_tm;
  95         int temp_tod2;
  96         int ret;
  97 
  98         rtc = dev_get_drvdata(dev);
  99 
 100         ret = regmap_read(rtc->regmap, CPCAP_REG_TOD2, &temp_tod2);
 101         ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
 102         ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD1, &cpcap_tm.tod1);
 103         ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD2, &cpcap_tm.tod2);
 104 
 105         if (temp_tod2 > cpcap_tm.tod2)
 106                 ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
 107 
 108         if (ret) {
 109                 dev_err(dev, "Failed to read time\n");
 110                 return -EIO;
 111         }
 112 
 113         cpcap2rtc_time(tm, &cpcap_tm);
 114 
 115         return 0;
 116 }
 117 
 118 static int cpcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
 119 {
 120         struct cpcap_rtc *rtc;
 121         struct cpcap_time cpcap_tm;
 122         int ret = 0;
 123 
 124         rtc = dev_get_drvdata(dev);
 125 
 126         rtc2cpcap_time(&cpcap_tm, tm);
 127 
 128         if (rtc->alarm_enabled)
 129                 disable_irq(rtc->alarm_irq);
 130         if (rtc->update_enabled)
 131                 disable_irq(rtc->update_irq);
 132 
 133         if (rtc->vendor == CPCAP_VENDOR_ST) {
 134                 /* The TOD1 and TOD2 registers MUST be written in this order
 135                  * for the change to properly set.
 136                  */
 137                 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
 138                                           TOD1_MASK, cpcap_tm.tod1);
 139                 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
 140                                           TOD2_MASK, cpcap_tm.tod2);
 141                 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
 142                                           DAY_MASK, cpcap_tm.day);
 143         } else {
 144                 /* Clearing the upper lower 8 bits of the TOD guarantees that
 145                  * the upper half of TOD (TOD2) will not increment for 0xFF RTC
 146                  * ticks (255 seconds).  During this time we can safely write
 147                  * to DAY, TOD2, then TOD1 (in that order) and expect RTC to be
 148                  * synchronized to the exact time requested upon the final write
 149                  * to TOD1.
 150                  */
 151                 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
 152                                           TOD1_MASK, 0);
 153                 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
 154                                           DAY_MASK, cpcap_tm.day);
 155                 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
 156                                           TOD2_MASK, cpcap_tm.tod2);
 157                 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
 158                                           TOD1_MASK, cpcap_tm.tod1);
 159         }
 160 
 161         if (rtc->update_enabled)
 162                 enable_irq(rtc->update_irq);
 163         if (rtc->alarm_enabled)
 164                 enable_irq(rtc->alarm_irq);
 165 
 166         return ret;
 167 }
 168 
 169 static int cpcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 170 {
 171         struct cpcap_rtc *rtc;
 172         struct cpcap_time cpcap_tm;
 173         int ret;
 174 
 175         rtc = dev_get_drvdata(dev);
 176 
 177         alrm->enabled = rtc->alarm_enabled;
 178 
 179         ret = regmap_read(rtc->regmap, CPCAP_REG_DAYA, &cpcap_tm.day);
 180         ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA2, &cpcap_tm.tod2);
 181         ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA1, &cpcap_tm.tod1);
 182 
 183         if (ret) {
 184                 dev_err(dev, "Failed to read time\n");
 185                 return -EIO;
 186         }
 187 
 188         cpcap2rtc_time(&alrm->time, &cpcap_tm);
 189         return rtc_valid_tm(&alrm->time);
 190 }
 191 
 192 static int cpcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 193 {
 194         struct cpcap_rtc *rtc;
 195         struct cpcap_time cpcap_tm;
 196         int ret;
 197 
 198         rtc = dev_get_drvdata(dev);
 199 
 200         rtc2cpcap_time(&cpcap_tm, &alrm->time);
 201 
 202         if (rtc->alarm_enabled)
 203                 disable_irq(rtc->alarm_irq);
 204 
 205         ret = regmap_update_bits(rtc->regmap, CPCAP_REG_DAYA, DAY_MASK,
 206                                  cpcap_tm.day);
 207         ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA2, TOD2_MASK,
 208                                   cpcap_tm.tod2);
 209         ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA1, TOD1_MASK,
 210                                   cpcap_tm.tod1);
 211 
 212         if (!ret) {
 213                 enable_irq(rtc->alarm_irq);
 214                 rtc->alarm_enabled = true;
 215         }
 216 
 217         return ret;
 218 }
 219 
 220 static const struct rtc_class_ops cpcap_rtc_ops = {
 221         .read_time              = cpcap_rtc_read_time,
 222         .set_time               = cpcap_rtc_set_time,
 223         .read_alarm             = cpcap_rtc_read_alarm,
 224         .set_alarm              = cpcap_rtc_set_alarm,
 225         .alarm_irq_enable       = cpcap_rtc_alarm_irq_enable,
 226 };
 227 
 228 static irqreturn_t cpcap_rtc_alarm_irq(int irq, void *data)
 229 {
 230         struct cpcap_rtc *rtc = data;
 231 
 232         rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
 233         return IRQ_HANDLED;
 234 }
 235 
 236 static irqreturn_t cpcap_rtc_update_irq(int irq, void *data)
 237 {
 238         struct cpcap_rtc *rtc = data;
 239 
 240         rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
 241         return IRQ_HANDLED;
 242 }
 243 
 244 static int cpcap_rtc_probe(struct platform_device *pdev)
 245 {
 246         struct device *dev = &pdev->dev;
 247         struct cpcap_rtc *rtc;
 248         int err;
 249 
 250         rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
 251         if (!rtc)
 252                 return -ENOMEM;
 253 
 254         rtc->regmap = dev_get_regmap(dev->parent, NULL);
 255         if (!rtc->regmap)
 256                 return -ENODEV;
 257 
 258         platform_set_drvdata(pdev, rtc);
 259         rtc->rtc_dev = devm_rtc_device_register(dev, "cpcap_rtc",
 260                                                 &cpcap_rtc_ops, THIS_MODULE);
 261 
 262         if (IS_ERR(rtc->rtc_dev))
 263                 return PTR_ERR(rtc->rtc_dev);
 264 
 265         err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor);
 266         if (err)
 267                 return err;
 268 
 269         rtc->alarm_irq = platform_get_irq(pdev, 0);
 270         err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
 271                                         cpcap_rtc_alarm_irq, IRQF_TRIGGER_NONE,
 272                                         "rtc_alarm", rtc);
 273         if (err) {
 274                 dev_err(dev, "Could not request alarm irq: %d\n", err);
 275                 return err;
 276         }
 277         disable_irq(rtc->alarm_irq);
 278 
 279         /* Stock Android uses the 1 Hz interrupt for "secure clock daemon",
 280          * which is not supported by the mainline kernel. The mainline kernel
 281          * does not use the irq at the moment, but we explicitly request and
 282          * disable it, so that its masked and does not wake up the processor
 283          * every second.
 284          */
 285         rtc->update_irq = platform_get_irq(pdev, 1);
 286         err = devm_request_threaded_irq(dev, rtc->update_irq, NULL,
 287                                         cpcap_rtc_update_irq, IRQF_TRIGGER_NONE,
 288                                         "rtc_1hz", rtc);
 289         if (err) {
 290                 dev_err(dev, "Could not request update irq: %d\n", err);
 291                 return err;
 292         }
 293         disable_irq(rtc->update_irq);
 294 
 295         err = device_init_wakeup(dev, 1);
 296         if (err) {
 297                 dev_err(dev, "wakeup initialization failed (%d)\n", err);
 298                 /* ignore error and continue without wakeup support */
 299         }
 300 
 301         return 0;
 302 }
 303 
 304 static const struct of_device_id cpcap_rtc_of_match[] = {
 305         { .compatible = "motorola,cpcap-rtc", },
 306         {},
 307 };
 308 MODULE_DEVICE_TABLE(of, cpcap_rtc_of_match);
 309 
 310 static struct platform_driver cpcap_rtc_driver = {
 311         .probe          = cpcap_rtc_probe,
 312         .driver         = {
 313                 .name   = "cpcap-rtc",
 314                 .of_match_table = cpcap_rtc_of_match,
 315         },
 316 };
 317 
 318 module_platform_driver(cpcap_rtc_driver);
 319 
 320 MODULE_ALIAS("platform:cpcap-rtc");
 321 MODULE_DESCRIPTION("CPCAP RTC driver");
 322 MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
 323 MODULE_LICENSE("GPL");

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