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