1a3a42806SGregory CLEMENT /* 2a3a42806SGregory CLEMENT * RTC driver for the Armada 38x Marvell SoCs 3a3a42806SGregory CLEMENT * 4a3a42806SGregory CLEMENT * Copyright (C) 2015 Marvell 5a3a42806SGregory CLEMENT * 6a3a42806SGregory CLEMENT * Gregory Clement <gregory.clement@free-electrons.com> 7a3a42806SGregory CLEMENT * 8a3a42806SGregory CLEMENT * This program is free software; you can redistribute it and/or 9a3a42806SGregory CLEMENT * modify it under the terms of the GNU General Public License as 10a3a42806SGregory CLEMENT * published by the Free Software Foundation; either version 2 of the 11a3a42806SGregory CLEMENT * License, or (at your option) any later version. 12a3a42806SGregory CLEMENT * 13a3a42806SGregory CLEMENT */ 14a3a42806SGregory CLEMENT 15a3a42806SGregory CLEMENT #include <linux/delay.h> 16a3a42806SGregory CLEMENT #include <linux/io.h> 17a3a42806SGregory CLEMENT #include <linux/module.h> 18a3a42806SGregory CLEMENT #include <linux/of.h> 19*75faea91SGregory CLEMENT #include <linux/of_device.h> 20a3a42806SGregory CLEMENT #include <linux/platform_device.h> 21a3a42806SGregory CLEMENT #include <linux/rtc.h> 22a3a42806SGregory CLEMENT 23a3a42806SGregory CLEMENT #define RTC_STATUS 0x0 24a3a42806SGregory CLEMENT #define RTC_STATUS_ALARM1 BIT(0) 25a3a42806SGregory CLEMENT #define RTC_STATUS_ALARM2 BIT(1) 26a3a42806SGregory CLEMENT #define RTC_IRQ1_CONF 0x4 27*75faea91SGregory CLEMENT #define RTC_IRQ_AL_EN BIT(0) 28*75faea91SGregory CLEMENT #define RTC_IRQ_FREQ_EN BIT(1) 29*75faea91SGregory CLEMENT #define RTC_IRQ_FREQ_1HZ BIT(2) 30*75faea91SGregory CLEMENT 31a3a42806SGregory CLEMENT #define RTC_TIME 0xC 32a3a42806SGregory CLEMENT #define RTC_ALARM1 0x10 33*75faea91SGregory CLEMENT #define RTC_38X_BRIDGE_TIMING_CTL 0x0 34*75faea91SGregory CLEMENT #define RTC_38X_PERIOD_OFFS 0 35*75faea91SGregory CLEMENT #define RTC_38X_PERIOD_MASK (0x3FF << RTC_38X_PERIOD_OFFS) 36*75faea91SGregory CLEMENT #define RTC_38X_READ_DELAY_OFFS 26 37*75faea91SGregory CLEMENT #define RTC_38X_READ_DELAY_MASK (0x1F << RTC_38X_READ_DELAY_OFFS) 38844a3073SGregory CLEMENT 39a3a42806SGregory CLEMENT #define SOC_RTC_INTERRUPT 0x8 40a3a42806SGregory CLEMENT #define SOC_RTC_ALARM1 BIT(0) 41a3a42806SGregory CLEMENT #define SOC_RTC_ALARM2 BIT(1) 42a3a42806SGregory CLEMENT #define SOC_RTC_ALARM1_MASK BIT(2) 43a3a42806SGregory CLEMENT #define SOC_RTC_ALARM2_MASK BIT(3) 44a3a42806SGregory CLEMENT 45844a3073SGregory CLEMENT #define SAMPLE_NR 100 46844a3073SGregory CLEMENT 47844a3073SGregory CLEMENT struct value_to_freq { 48844a3073SGregory CLEMENT u32 value; 49844a3073SGregory CLEMENT u8 freq; 50844a3073SGregory CLEMENT }; 51844a3073SGregory CLEMENT 52a3a42806SGregory CLEMENT struct armada38x_rtc { 53a3a42806SGregory CLEMENT struct rtc_device *rtc_dev; 54a3a42806SGregory CLEMENT void __iomem *regs; 55a3a42806SGregory CLEMENT void __iomem *regs_soc; 56a3a42806SGregory CLEMENT spinlock_t lock; 57a3a42806SGregory CLEMENT int irq; 58844a3073SGregory CLEMENT struct value_to_freq *val_to_freq; 59*75faea91SGregory CLEMENT struct armada38x_rtc_data *data; 60*75faea91SGregory CLEMENT }; 61*75faea91SGregory CLEMENT 62*75faea91SGregory CLEMENT #define ALARM1 0 63*75faea91SGregory CLEMENT #define ALARM_REG(base, alarm) ((base) + (alarm) * sizeof(u32)) 64*75faea91SGregory CLEMENT 65*75faea91SGregory CLEMENT struct armada38x_rtc_data { 66*75faea91SGregory CLEMENT /* Initialize the RTC-MBUS bridge timing */ 67*75faea91SGregory CLEMENT void (*update_mbus_timing)(struct armada38x_rtc *rtc); 68*75faea91SGregory CLEMENT u32 (*read_rtc_reg)(struct armada38x_rtc *rtc, u8 rtc_reg); 69*75faea91SGregory CLEMENT void (*clear_isr)(struct armada38x_rtc *rtc); 70*75faea91SGregory CLEMENT void (*unmask_interrupt)(struct armada38x_rtc *rtc); 71*75faea91SGregory CLEMENT u32 alarm; 72a3a42806SGregory CLEMENT }; 73a3a42806SGregory CLEMENT 74a3a42806SGregory CLEMENT /* 75a3a42806SGregory CLEMENT * According to the datasheet, the OS should wait 5us after every 76a3a42806SGregory CLEMENT * register write to the RTC hard macro so that the required update 77a3a42806SGregory CLEMENT * can occur without holding off the system bus 78844a3073SGregory CLEMENT * According to errata RES-3124064, Write to any RTC register 79844a3073SGregory CLEMENT * may fail. As a workaround, before writing to RTC 80844a3073SGregory CLEMENT * register, issue a dummy write of 0x0 twice to RTC Status 81844a3073SGregory CLEMENT * register. 82a3a42806SGregory CLEMENT */ 83844a3073SGregory CLEMENT 84a3a42806SGregory CLEMENT static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset) 85a3a42806SGregory CLEMENT { 86844a3073SGregory CLEMENT writel(0, rtc->regs + RTC_STATUS); 87844a3073SGregory CLEMENT writel(0, rtc->regs + RTC_STATUS); 88a3a42806SGregory CLEMENT writel(val, rtc->regs + offset); 89a3a42806SGregory CLEMENT udelay(5); 90a3a42806SGregory CLEMENT } 91a3a42806SGregory CLEMENT 92844a3073SGregory CLEMENT /* Update RTC-MBUS bridge timing parameters */ 93*75faea91SGregory CLEMENT static void rtc_update_38x_mbus_timing_params(struct armada38x_rtc *rtc) 94844a3073SGregory CLEMENT { 95844a3073SGregory CLEMENT u32 reg; 96844a3073SGregory CLEMENT 97*75faea91SGregory CLEMENT reg = readl(rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL); 98*75faea91SGregory CLEMENT reg &= ~RTC_38X_PERIOD_MASK; 99*75faea91SGregory CLEMENT reg |= 0x3FF << RTC_38X_PERIOD_OFFS; /* Maximum value */ 100*75faea91SGregory CLEMENT reg &= ~RTC_38X_READ_DELAY_MASK; 101*75faea91SGregory CLEMENT reg |= 0x1F << RTC_38X_READ_DELAY_OFFS; /* Maximum value */ 102*75faea91SGregory CLEMENT writel(reg, rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL); 103844a3073SGregory CLEMENT } 104844a3073SGregory CLEMENT 105*75faea91SGregory CLEMENT static u32 read_rtc_register_38x_wa(struct armada38x_rtc *rtc, u8 rtc_reg) 106844a3073SGregory CLEMENT { 107844a3073SGregory CLEMENT int i, index_max = 0, max = 0; 108844a3073SGregory CLEMENT 109844a3073SGregory CLEMENT for (i = 0; i < SAMPLE_NR; i++) { 110844a3073SGregory CLEMENT rtc->val_to_freq[i].value = readl(rtc->regs + rtc_reg); 111844a3073SGregory CLEMENT rtc->val_to_freq[i].freq = 0; 112844a3073SGregory CLEMENT } 113844a3073SGregory CLEMENT 114844a3073SGregory CLEMENT for (i = 0; i < SAMPLE_NR; i++) { 115844a3073SGregory CLEMENT int j = 0; 116844a3073SGregory CLEMENT u32 value = rtc->val_to_freq[i].value; 117844a3073SGregory CLEMENT 118844a3073SGregory CLEMENT while (rtc->val_to_freq[j].freq) { 119844a3073SGregory CLEMENT if (rtc->val_to_freq[j].value == value) { 120844a3073SGregory CLEMENT rtc->val_to_freq[j].freq++; 121844a3073SGregory CLEMENT break; 122844a3073SGregory CLEMENT } 123844a3073SGregory CLEMENT j++; 124844a3073SGregory CLEMENT } 125844a3073SGregory CLEMENT 126844a3073SGregory CLEMENT if (!rtc->val_to_freq[j].freq) { 127844a3073SGregory CLEMENT rtc->val_to_freq[j].value = value; 128844a3073SGregory CLEMENT rtc->val_to_freq[j].freq = 1; 129844a3073SGregory CLEMENT } 130844a3073SGregory CLEMENT 131844a3073SGregory CLEMENT if (rtc->val_to_freq[j].freq > max) { 132844a3073SGregory CLEMENT index_max = j; 133844a3073SGregory CLEMENT max = rtc->val_to_freq[j].freq; 134844a3073SGregory CLEMENT } 135844a3073SGregory CLEMENT 136844a3073SGregory CLEMENT /* 137844a3073SGregory CLEMENT * If a value already has half of the sample this is the most 138844a3073SGregory CLEMENT * frequent one and we can stop the research right now 139844a3073SGregory CLEMENT */ 140844a3073SGregory CLEMENT if (max > SAMPLE_NR / 2) 141844a3073SGregory CLEMENT break; 142844a3073SGregory CLEMENT } 143844a3073SGregory CLEMENT 144844a3073SGregory CLEMENT return rtc->val_to_freq[index_max].value; 145844a3073SGregory CLEMENT } 146844a3073SGregory CLEMENT 147*75faea91SGregory CLEMENT static void armada38x_clear_isr(struct armada38x_rtc *rtc) 148*75faea91SGregory CLEMENT { 149*75faea91SGregory CLEMENT u32 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT); 150*75faea91SGregory CLEMENT 151*75faea91SGregory CLEMENT writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT); 152*75faea91SGregory CLEMENT } 153*75faea91SGregory CLEMENT 154*75faea91SGregory CLEMENT static void armada38x_unmask_interrupt(struct armada38x_rtc *rtc) 155*75faea91SGregory CLEMENT { 156*75faea91SGregory CLEMENT u32 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT); 157*75faea91SGregory CLEMENT 158*75faea91SGregory CLEMENT writel(val | SOC_RTC_ALARM1_MASK, rtc->regs_soc + SOC_RTC_INTERRUPT); 159*75faea91SGregory CLEMENT } 160a3a42806SGregory CLEMENT static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) 161a3a42806SGregory CLEMENT { 162a3a42806SGregory CLEMENT struct armada38x_rtc *rtc = dev_get_drvdata(dev); 163844a3073SGregory CLEMENT unsigned long time, flags; 164a3a42806SGregory CLEMENT 1650c6e7183SNadav Haklai spin_lock_irqsave(&rtc->lock, flags); 166*75faea91SGregory CLEMENT time = rtc->data->read_rtc_reg(rtc, RTC_TIME); 1670c6e7183SNadav Haklai spin_unlock_irqrestore(&rtc->lock, flags); 168a3a42806SGregory CLEMENT 169844a3073SGregory CLEMENT rtc_time_to_tm(time, tm); 170a3a42806SGregory CLEMENT 171a3a42806SGregory CLEMENT return 0; 172a3a42806SGregory CLEMENT } 173a3a42806SGregory CLEMENT 174a3a42806SGregory CLEMENT static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm) 175a3a42806SGregory CLEMENT { 176a3a42806SGregory CLEMENT struct armada38x_rtc *rtc = dev_get_drvdata(dev); 177a3a42806SGregory CLEMENT int ret = 0; 1780c6e7183SNadav Haklai unsigned long time, flags; 179a3a42806SGregory CLEMENT 180a3a42806SGregory CLEMENT ret = rtc_tm_to_time(tm, &time); 181a3a42806SGregory CLEMENT 182a3a42806SGregory CLEMENT if (ret) 183a3a42806SGregory CLEMENT goto out; 184844a3073SGregory CLEMENT 1850c6e7183SNadav Haklai spin_lock_irqsave(&rtc->lock, flags); 186a3a42806SGregory CLEMENT rtc_delayed_write(time, rtc, RTC_TIME); 1870c6e7183SNadav Haklai spin_unlock_irqrestore(&rtc->lock, flags); 188a3a42806SGregory CLEMENT 189a3a42806SGregory CLEMENT out: 190a3a42806SGregory CLEMENT return ret; 191a3a42806SGregory CLEMENT } 192a3a42806SGregory CLEMENT 193a3a42806SGregory CLEMENT static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 194a3a42806SGregory CLEMENT { 195a3a42806SGregory CLEMENT struct armada38x_rtc *rtc = dev_get_drvdata(dev); 196a3a42806SGregory CLEMENT unsigned long time, flags; 197*75faea91SGregory CLEMENT u32 reg = ALARM_REG(RTC_ALARM1, rtc->data->alarm); 198*75faea91SGregory CLEMENT u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm); 199a3a42806SGregory CLEMENT u32 val; 200a3a42806SGregory CLEMENT 201a3a42806SGregory CLEMENT spin_lock_irqsave(&rtc->lock, flags); 202a3a42806SGregory CLEMENT 203*75faea91SGregory CLEMENT time = rtc->data->read_rtc_reg(rtc, reg); 204*75faea91SGregory CLEMENT val = rtc->data->read_rtc_reg(rtc, reg_irq) & RTC_IRQ_AL_EN; 205a3a42806SGregory CLEMENT 206a3a42806SGregory CLEMENT spin_unlock_irqrestore(&rtc->lock, flags); 207a3a42806SGregory CLEMENT 208a3a42806SGregory CLEMENT alrm->enabled = val ? 1 : 0; 209a3a42806SGregory CLEMENT rtc_time_to_tm(time, &alrm->time); 210a3a42806SGregory CLEMENT 211a3a42806SGregory CLEMENT return 0; 212a3a42806SGregory CLEMENT } 213a3a42806SGregory CLEMENT 214a3a42806SGregory CLEMENT static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 215a3a42806SGregory CLEMENT { 216a3a42806SGregory CLEMENT struct armada38x_rtc *rtc = dev_get_drvdata(dev); 217*75faea91SGregory CLEMENT u32 reg = ALARM_REG(RTC_ALARM1, rtc->data->alarm); 218*75faea91SGregory CLEMENT u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm); 219a3a42806SGregory CLEMENT unsigned long time, flags; 220a3a42806SGregory CLEMENT int ret = 0; 221a3a42806SGregory CLEMENT 222a3a42806SGregory CLEMENT ret = rtc_tm_to_time(&alrm->time, &time); 223a3a42806SGregory CLEMENT 224a3a42806SGregory CLEMENT if (ret) 225a3a42806SGregory CLEMENT goto out; 226a3a42806SGregory CLEMENT 227a3a42806SGregory CLEMENT spin_lock_irqsave(&rtc->lock, flags); 228a3a42806SGregory CLEMENT 229*75faea91SGregory CLEMENT rtc_delayed_write(time, rtc, reg); 230a3a42806SGregory CLEMENT 231a3a42806SGregory CLEMENT if (alrm->enabled) { 232*75faea91SGregory CLEMENT rtc_delayed_write(RTC_IRQ_AL_EN, rtc, reg_irq); 233*75faea91SGregory CLEMENT rtc->data->unmask_interrupt(rtc); 234a3a42806SGregory CLEMENT } 235a3a42806SGregory CLEMENT 236a3a42806SGregory CLEMENT spin_unlock_irqrestore(&rtc->lock, flags); 237a3a42806SGregory CLEMENT 238a3a42806SGregory CLEMENT out: 239a3a42806SGregory CLEMENT return ret; 240a3a42806SGregory CLEMENT } 241a3a42806SGregory CLEMENT 242a3a42806SGregory CLEMENT static int armada38x_rtc_alarm_irq_enable(struct device *dev, 243a3a42806SGregory CLEMENT unsigned int enabled) 244a3a42806SGregory CLEMENT { 245a3a42806SGregory CLEMENT struct armada38x_rtc *rtc = dev_get_drvdata(dev); 246*75faea91SGregory CLEMENT u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm); 247a3a42806SGregory CLEMENT unsigned long flags; 248a3a42806SGregory CLEMENT 249a3a42806SGregory CLEMENT spin_lock_irqsave(&rtc->lock, flags); 250a3a42806SGregory CLEMENT 251a3a42806SGregory CLEMENT if (enabled) 252*75faea91SGregory CLEMENT rtc_delayed_write(RTC_IRQ_AL_EN, rtc, reg_irq); 253a3a42806SGregory CLEMENT else 254*75faea91SGregory CLEMENT rtc_delayed_write(0, rtc, reg_irq); 255a3a42806SGregory CLEMENT 256a3a42806SGregory CLEMENT spin_unlock_irqrestore(&rtc->lock, flags); 257a3a42806SGregory CLEMENT 258a3a42806SGregory CLEMENT return 0; 259a3a42806SGregory CLEMENT } 260a3a42806SGregory CLEMENT 261a3a42806SGregory CLEMENT static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data) 262a3a42806SGregory CLEMENT { 263a3a42806SGregory CLEMENT struct armada38x_rtc *rtc = data; 264a3a42806SGregory CLEMENT u32 val; 265a3a42806SGregory CLEMENT int event = RTC_IRQF | RTC_AF; 266*75faea91SGregory CLEMENT u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm); 267a3a42806SGregory CLEMENT 268a3a42806SGregory CLEMENT dev_dbg(&rtc->rtc_dev->dev, "%s:irq(%d)\n", __func__, irq); 269a3a42806SGregory CLEMENT 270a3a42806SGregory CLEMENT spin_lock(&rtc->lock); 271a3a42806SGregory CLEMENT 272*75faea91SGregory CLEMENT rtc->data->clear_isr(rtc); 273*75faea91SGregory CLEMENT val = rtc->data->read_rtc_reg(rtc, reg_irq); 274*75faea91SGregory CLEMENT /* disable all the interrupts for alarm*/ 275*75faea91SGregory CLEMENT rtc_delayed_write(0, rtc, reg_irq); 276a3a42806SGregory CLEMENT /* Ack the event */ 277*75faea91SGregory CLEMENT rtc_delayed_write(1 << rtc->data->alarm, rtc, RTC_STATUS); 278a3a42806SGregory CLEMENT 279a3a42806SGregory CLEMENT spin_unlock(&rtc->lock); 280a3a42806SGregory CLEMENT 281*75faea91SGregory CLEMENT if (val & RTC_IRQ_FREQ_EN) { 282*75faea91SGregory CLEMENT if (val & RTC_IRQ_FREQ_1HZ) 283a3a42806SGregory CLEMENT event |= RTC_UF; 284a3a42806SGregory CLEMENT else 285a3a42806SGregory CLEMENT event |= RTC_PF; 286a3a42806SGregory CLEMENT } 287a3a42806SGregory CLEMENT 288a3a42806SGregory CLEMENT rtc_update_irq(rtc->rtc_dev, 1, event); 289a3a42806SGregory CLEMENT 290a3a42806SGregory CLEMENT return IRQ_HANDLED; 291a3a42806SGregory CLEMENT } 292a3a42806SGregory CLEMENT 293d748c981SRussell King static const struct rtc_class_ops armada38x_rtc_ops = { 294a3a42806SGregory CLEMENT .read_time = armada38x_rtc_read_time, 295a3a42806SGregory CLEMENT .set_time = armada38x_rtc_set_time, 296a3a42806SGregory CLEMENT .read_alarm = armada38x_rtc_read_alarm, 297a3a42806SGregory CLEMENT .set_alarm = armada38x_rtc_set_alarm, 298a3a42806SGregory CLEMENT .alarm_irq_enable = armada38x_rtc_alarm_irq_enable, 299a3a42806SGregory CLEMENT }; 300a3a42806SGregory CLEMENT 301d748c981SRussell King static const struct rtc_class_ops armada38x_rtc_ops_noirq = { 302d748c981SRussell King .read_time = armada38x_rtc_read_time, 303d748c981SRussell King .set_time = armada38x_rtc_set_time, 304d748c981SRussell King .read_alarm = armada38x_rtc_read_alarm, 305d748c981SRussell King }; 306d748c981SRussell King 307*75faea91SGregory CLEMENT static const struct armada38x_rtc_data armada38x_data = { 308*75faea91SGregory CLEMENT .update_mbus_timing = rtc_update_38x_mbus_timing_params, 309*75faea91SGregory CLEMENT .read_rtc_reg = read_rtc_register_38x_wa, 310*75faea91SGregory CLEMENT .clear_isr = armada38x_clear_isr, 311*75faea91SGregory CLEMENT .unmask_interrupt = armada38x_unmask_interrupt, 312*75faea91SGregory CLEMENT .alarm = ALARM1, 313*75faea91SGregory CLEMENT }; 314*75faea91SGregory CLEMENT 315*75faea91SGregory CLEMENT #ifdef CONFIG_OF 316*75faea91SGregory CLEMENT static const struct of_device_id armada38x_rtc_of_match_table[] = { 317*75faea91SGregory CLEMENT { 318*75faea91SGregory CLEMENT .compatible = "marvell,armada-380-rtc", 319*75faea91SGregory CLEMENT .data = &armada38x_data, 320*75faea91SGregory CLEMENT }, 321*75faea91SGregory CLEMENT {} 322*75faea91SGregory CLEMENT }; 323*75faea91SGregory CLEMENT MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table); 324*75faea91SGregory CLEMENT #endif 325*75faea91SGregory CLEMENT 326a3a42806SGregory CLEMENT static __init int armada38x_rtc_probe(struct platform_device *pdev) 327a3a42806SGregory CLEMENT { 328d748c981SRussell King const struct rtc_class_ops *ops; 329a3a42806SGregory CLEMENT struct resource *res; 330a3a42806SGregory CLEMENT struct armada38x_rtc *rtc; 331*75faea91SGregory CLEMENT const struct of_device_id *match; 332a3a42806SGregory CLEMENT int ret; 333a3a42806SGregory CLEMENT 334*75faea91SGregory CLEMENT match = of_match_device(armada38x_rtc_of_match_table, &pdev->dev); 335*75faea91SGregory CLEMENT if (!match) 336*75faea91SGregory CLEMENT return -ENODEV; 337*75faea91SGregory CLEMENT 338a3a42806SGregory CLEMENT rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc), 339a3a42806SGregory CLEMENT GFP_KERNEL); 340a3a42806SGregory CLEMENT if (!rtc) 341a3a42806SGregory CLEMENT return -ENOMEM; 342a3a42806SGregory CLEMENT 343844a3073SGregory CLEMENT rtc->val_to_freq = devm_kcalloc(&pdev->dev, SAMPLE_NR, 344844a3073SGregory CLEMENT sizeof(struct value_to_freq), GFP_KERNEL); 345844a3073SGregory CLEMENT if (!rtc->val_to_freq) 346844a3073SGregory CLEMENT return -ENOMEM; 347844a3073SGregory CLEMENT 348a3a42806SGregory CLEMENT spin_lock_init(&rtc->lock); 349a3a42806SGregory CLEMENT 350a3a42806SGregory CLEMENT res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc"); 351a3a42806SGregory CLEMENT rtc->regs = devm_ioremap_resource(&pdev->dev, res); 352a3a42806SGregory CLEMENT if (IS_ERR(rtc->regs)) 353a3a42806SGregory CLEMENT return PTR_ERR(rtc->regs); 354a3a42806SGregory CLEMENT res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc-soc"); 355a3a42806SGregory CLEMENT rtc->regs_soc = devm_ioremap_resource(&pdev->dev, res); 356a3a42806SGregory CLEMENT if (IS_ERR(rtc->regs_soc)) 357a3a42806SGregory CLEMENT return PTR_ERR(rtc->regs_soc); 358a3a42806SGregory CLEMENT 359a3a42806SGregory CLEMENT rtc->irq = platform_get_irq(pdev, 0); 360a3a42806SGregory CLEMENT 361a3a42806SGregory CLEMENT if (rtc->irq < 0) { 362a3a42806SGregory CLEMENT dev_err(&pdev->dev, "no irq\n"); 363a3a42806SGregory CLEMENT return rtc->irq; 364a3a42806SGregory CLEMENT } 365a3a42806SGregory CLEMENT if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq, 366a3a42806SGregory CLEMENT 0, pdev->name, rtc) < 0) { 367a3a42806SGregory CLEMENT dev_warn(&pdev->dev, "Interrupt not available.\n"); 368a3a42806SGregory CLEMENT rtc->irq = -1; 369d748c981SRussell King } 370d748c981SRussell King platform_set_drvdata(pdev, rtc); 371d748c981SRussell King 372d748c981SRussell King if (rtc->irq != -1) { 373d748c981SRussell King device_init_wakeup(&pdev->dev, 1); 374d748c981SRussell King ops = &armada38x_rtc_ops; 375d748c981SRussell King } else { 376a3a42806SGregory CLEMENT /* 377a3a42806SGregory CLEMENT * If there is no interrupt available then we can't 378a3a42806SGregory CLEMENT * use the alarm 379a3a42806SGregory CLEMENT */ 380d748c981SRussell King ops = &armada38x_rtc_ops_noirq; 381a3a42806SGregory CLEMENT } 382*75faea91SGregory CLEMENT rtc->data = (struct armada38x_rtc_data *)match->data; 383*75faea91SGregory CLEMENT 384a3a42806SGregory CLEMENT 385844a3073SGregory CLEMENT /* Update RTC-MBUS bridge timing parameters */ 386*75faea91SGregory CLEMENT rtc->data->update_mbus_timing(rtc); 387844a3073SGregory CLEMENT 388a3a42806SGregory CLEMENT rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name, 389d748c981SRussell King ops, THIS_MODULE); 390a3a42806SGregory CLEMENT if (IS_ERR(rtc->rtc_dev)) { 391a3a42806SGregory CLEMENT ret = PTR_ERR(rtc->rtc_dev); 392a3a42806SGregory CLEMENT dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); 393a3a42806SGregory CLEMENT return ret; 394a3a42806SGregory CLEMENT } 395a3a42806SGregory CLEMENT return 0; 396a3a42806SGregory CLEMENT } 397a3a42806SGregory CLEMENT 398a3a42806SGregory CLEMENT #ifdef CONFIG_PM_SLEEP 399a3a42806SGregory CLEMENT static int armada38x_rtc_suspend(struct device *dev) 400a3a42806SGregory CLEMENT { 401a3a42806SGregory CLEMENT if (device_may_wakeup(dev)) { 402a3a42806SGregory CLEMENT struct armada38x_rtc *rtc = dev_get_drvdata(dev); 403a3a42806SGregory CLEMENT 404a3a42806SGregory CLEMENT return enable_irq_wake(rtc->irq); 405a3a42806SGregory CLEMENT } 406a3a42806SGregory CLEMENT 407a3a42806SGregory CLEMENT return 0; 408a3a42806SGregory CLEMENT } 409a3a42806SGregory CLEMENT 410a3a42806SGregory CLEMENT static int armada38x_rtc_resume(struct device *dev) 411a3a42806SGregory CLEMENT { 412a3a42806SGregory CLEMENT if (device_may_wakeup(dev)) { 413a3a42806SGregory CLEMENT struct armada38x_rtc *rtc = dev_get_drvdata(dev); 414a3a42806SGregory CLEMENT 415844a3073SGregory CLEMENT /* Update RTC-MBUS bridge timing parameters */ 416*75faea91SGregory CLEMENT rtc->data->update_mbus_timing(rtc); 417844a3073SGregory CLEMENT 418a3a42806SGregory CLEMENT return disable_irq_wake(rtc->irq); 419a3a42806SGregory CLEMENT } 420a3a42806SGregory CLEMENT 421a3a42806SGregory CLEMENT return 0; 422a3a42806SGregory CLEMENT } 423a3a42806SGregory CLEMENT #endif 424a3a42806SGregory CLEMENT 425a3a42806SGregory CLEMENT static SIMPLE_DEV_PM_OPS(armada38x_rtc_pm_ops, 426a3a42806SGregory CLEMENT armada38x_rtc_suspend, armada38x_rtc_resume); 427a3a42806SGregory CLEMENT 428a3a42806SGregory CLEMENT static struct platform_driver armada38x_rtc_driver = { 429a3a42806SGregory CLEMENT .driver = { 430a3a42806SGregory CLEMENT .name = "armada38x-rtc", 431a3a42806SGregory CLEMENT .pm = &armada38x_rtc_pm_ops, 432a3a42806SGregory CLEMENT .of_match_table = of_match_ptr(armada38x_rtc_of_match_table), 433a3a42806SGregory CLEMENT }, 434a3a42806SGregory CLEMENT }; 435a3a42806SGregory CLEMENT 436a3a42806SGregory CLEMENT module_platform_driver_probe(armada38x_rtc_driver, armada38x_rtc_probe); 437a3a42806SGregory CLEMENT 438a3a42806SGregory CLEMENT MODULE_DESCRIPTION("Marvell Armada 38x RTC driver"); 439a3a42806SGregory CLEMENT MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>"); 440a3a42806SGregory CLEMENT MODULE_LICENSE("GPL"); 441