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