linux/drivers/rtc/rtc-xgene.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * APM X-Gene SoC Real Time Clock Driver
   4 *
   5 * Copyright (c) 2014, Applied Micro Circuits Corporation
   6 * Author: Rameshwar Prasad Sahu <rsahu@apm.com>
   7 *         Loc Ho <lho@apm.com>
   8 */
   9
  10#include <linux/clk.h>
  11#include <linux/delay.h>
  12#include <linux/init.h>
  13#include <linux/io.h>
  14#include <linux/module.h>
  15#include <linux/of.h>
  16#include <linux/platform_device.h>
  17#include <linux/rtc.h>
  18#include <linux/slab.h>
  19
  20/* RTC CSR Registers */
  21#define RTC_CCVR                0x00
  22#define RTC_CMR                 0x04
  23#define RTC_CLR                 0x08
  24#define RTC_CCR                 0x0C
  25#define  RTC_CCR_IE             BIT(0)
  26#define  RTC_CCR_MASK           BIT(1)
  27#define  RTC_CCR_EN             BIT(2)
  28#define  RTC_CCR_WEN            BIT(3)
  29#define RTC_STAT                0x10
  30#define  RTC_STAT_BIT           BIT(0)
  31#define RTC_RSTAT               0x14
  32#define RTC_EOI                 0x18
  33#define RTC_VER                 0x1C
  34
  35struct xgene_rtc_dev {
  36        struct rtc_device *rtc;
  37        void __iomem *csr_base;
  38        struct clk *clk;
  39        unsigned int irq_wake;
  40        unsigned int irq_enabled;
  41};
  42
  43static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm)
  44{
  45        struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
  46
  47        rtc_time64_to_tm(readl(pdata->csr_base + RTC_CCVR), tm);
  48        return 0;
  49}
  50
  51static int xgene_rtc_set_time(struct device *dev, struct rtc_time *tm)
  52{
  53        struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
  54
  55        /*
  56         * NOTE: After the following write, the RTC_CCVR is only reflected
  57         *       after the update cycle of 1 seconds.
  58         */
  59        writel((u32)rtc_tm_to_time64(tm), pdata->csr_base + RTC_CLR);
  60        readl(pdata->csr_base + RTC_CLR); /* Force a barrier */
  61
  62        return 0;
  63}
  64
  65static int xgene_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  66{
  67        struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
  68
  69        /* If possible, CMR should be read here */
  70        rtc_time64_to_tm(0, &alrm->time);
  71        alrm->enabled = readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE;
  72
  73        return 0;
  74}
  75
  76static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled)
  77{
  78        struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
  79        u32 ccr;
  80
  81        ccr = readl(pdata->csr_base + RTC_CCR);
  82        if (enabled) {
  83                ccr &= ~RTC_CCR_MASK;
  84                ccr |= RTC_CCR_IE;
  85        } else {
  86                ccr &= ~RTC_CCR_IE;
  87                ccr |= RTC_CCR_MASK;
  88        }
  89        writel(ccr, pdata->csr_base + RTC_CCR);
  90
  91        return 0;
  92}
  93
  94static int xgene_rtc_alarm_irq_enabled(struct device *dev)
  95{
  96        struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
  97
  98        return readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE ? 1 : 0;
  99}
 100
 101static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 102{
 103        struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
 104
 105        writel((u32)rtc_tm_to_time64(&alrm->time), pdata->csr_base + RTC_CMR);
 106
 107        xgene_rtc_alarm_irq_enable(dev, alrm->enabled);
 108
 109        return 0;
 110}
 111
 112static const struct rtc_class_ops xgene_rtc_ops = {
 113        .read_time      = xgene_rtc_read_time,
 114        .set_time       = xgene_rtc_set_time,
 115        .read_alarm     = xgene_rtc_read_alarm,
 116        .set_alarm      = xgene_rtc_set_alarm,
 117        .alarm_irq_enable = xgene_rtc_alarm_irq_enable,
 118};
 119
 120static irqreturn_t xgene_rtc_interrupt(int irq, void *id)
 121{
 122        struct xgene_rtc_dev *pdata = id;
 123
 124        /* Check if interrupt asserted */
 125        if (!(readl(pdata->csr_base + RTC_STAT) & RTC_STAT_BIT))
 126                return IRQ_NONE;
 127
 128        /* Clear interrupt */
 129        readl(pdata->csr_base + RTC_EOI);
 130
 131        rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF);
 132
 133        return IRQ_HANDLED;
 134}
 135
 136static int xgene_rtc_probe(struct platform_device *pdev)
 137{
 138        struct xgene_rtc_dev *pdata;
 139        int ret;
 140        int irq;
 141
 142        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 143        if (!pdata)
 144                return -ENOMEM;
 145        platform_set_drvdata(pdev, pdata);
 146
 147        pdata->csr_base = devm_platform_ioremap_resource(pdev, 0);
 148        if (IS_ERR(pdata->csr_base))
 149                return PTR_ERR(pdata->csr_base);
 150
 151        pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
 152        if (IS_ERR(pdata->rtc))
 153                return PTR_ERR(pdata->rtc);
 154
 155        irq = platform_get_irq(pdev, 0);
 156        if (irq < 0)
 157                return irq;
 158        ret = devm_request_irq(&pdev->dev, irq, xgene_rtc_interrupt, 0,
 159                               dev_name(&pdev->dev), pdata);
 160        if (ret) {
 161                dev_err(&pdev->dev, "Could not request IRQ\n");
 162                return ret;
 163        }
 164
 165        pdata->clk = devm_clk_get(&pdev->dev, NULL);
 166        if (IS_ERR(pdata->clk)) {
 167                dev_err(&pdev->dev, "Couldn't get the clock for RTC\n");
 168                return -ENODEV;
 169        }
 170        ret = clk_prepare_enable(pdata->clk);
 171        if (ret)
 172                return ret;
 173
 174        /* Turn on the clock and the crystal */
 175        writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR);
 176
 177        ret = device_init_wakeup(&pdev->dev, 1);
 178        if (ret) {
 179                clk_disable_unprepare(pdata->clk);
 180                return ret;
 181        }
 182
 183        /* HW does not support update faster than 1 seconds */
 184        pdata->rtc->uie_unsupported = 1;
 185        pdata->rtc->ops = &xgene_rtc_ops;
 186        pdata->rtc->range_max = U32_MAX;
 187
 188        ret = rtc_register_device(pdata->rtc);
 189        if (ret) {
 190                clk_disable_unprepare(pdata->clk);
 191                return ret;
 192        }
 193
 194        return 0;
 195}
 196
 197static int xgene_rtc_remove(struct platform_device *pdev)
 198{
 199        struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
 200
 201        xgene_rtc_alarm_irq_enable(&pdev->dev, 0);
 202        device_init_wakeup(&pdev->dev, 0);
 203        clk_disable_unprepare(pdata->clk);
 204        return 0;
 205}
 206
 207static int __maybe_unused xgene_rtc_suspend(struct device *dev)
 208{
 209        struct platform_device *pdev = to_platform_device(dev);
 210        struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
 211        int irq;
 212
 213        irq = platform_get_irq(pdev, 0);
 214
 215        /*
 216         * If this RTC alarm will be used for waking the system up,
 217         * don't disable it of course. Else we just disable the alarm
 218         * and await suspension.
 219         */
 220        if (device_may_wakeup(&pdev->dev)) {
 221                if (!enable_irq_wake(irq))
 222                        pdata->irq_wake = 1;
 223        } else {
 224                pdata->irq_enabled = xgene_rtc_alarm_irq_enabled(dev);
 225                xgene_rtc_alarm_irq_enable(dev, 0);
 226                clk_disable_unprepare(pdata->clk);
 227        }
 228        return 0;
 229}
 230
 231static int __maybe_unused xgene_rtc_resume(struct device *dev)
 232{
 233        struct platform_device *pdev = to_platform_device(dev);
 234        struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
 235        int irq;
 236        int rc;
 237
 238        irq = platform_get_irq(pdev, 0);
 239
 240        if (device_may_wakeup(&pdev->dev)) {
 241                if (pdata->irq_wake) {
 242                        disable_irq_wake(irq);
 243                        pdata->irq_wake = 0;
 244                }
 245        } else {
 246                rc = clk_prepare_enable(pdata->clk);
 247                if (rc) {
 248                        dev_err(dev, "Unable to enable clock error %d\n", rc);
 249                        return rc;
 250                }
 251                xgene_rtc_alarm_irq_enable(dev, pdata->irq_enabled);
 252        }
 253
 254        return 0;
 255}
 256
 257static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops, xgene_rtc_suspend, xgene_rtc_resume);
 258
 259#ifdef CONFIG_OF
 260static const struct of_device_id xgene_rtc_of_match[] = {
 261        {.compatible = "apm,xgene-rtc" },
 262        { }
 263};
 264MODULE_DEVICE_TABLE(of, xgene_rtc_of_match);
 265#endif
 266
 267static struct platform_driver xgene_rtc_driver = {
 268        .probe          = xgene_rtc_probe,
 269        .remove         = xgene_rtc_remove,
 270        .driver         = {
 271                .name   = "xgene-rtc",
 272                .pm = &xgene_rtc_pm_ops,
 273                .of_match_table = of_match_ptr(xgene_rtc_of_match),
 274        },
 275};
 276
 277module_platform_driver(xgene_rtc_driver);
 278
 279MODULE_DESCRIPTION("APM X-Gene SoC RTC driver");
 280MODULE_AUTHOR("Rameshwar Sahu <rsahu@apm.com>");
 281MODULE_LICENSE("GPL");
 282