15874c7f1SFabio Estevam // SPDX-License-Identifier: GPL-2.0+ 25874c7f1SFabio Estevam // 35874c7f1SFabio Estevam // Copyright (C) 2011-2012 Freescale Semiconductor, Inc. 4179a502fSShawn Guo 5179a502fSShawn Guo #include <linux/init.h> 6179a502fSShawn Guo #include <linux/io.h> 7179a502fSShawn Guo #include <linux/kernel.h> 8179a502fSShawn Guo #include <linux/module.h> 9179a502fSShawn Guo #include <linux/of.h> 10179a502fSShawn Guo #include <linux/of_device.h> 11179a502fSShawn Guo #include <linux/platform_device.h> 12*e7afddb2SAnson Huang #include <linux/pm_wakeirq.h> 13179a502fSShawn Guo #include <linux/rtc.h> 147f899399SSanchayan Maity #include <linux/clk.h> 15d482893bSFrank Li #include <linux/mfd/syscon.h> 16d482893bSFrank Li #include <linux/regmap.h> 17d482893bSFrank Li 18d482893bSFrank Li #define SNVS_LPREGISTER_OFFSET 0x34 19179a502fSShawn Guo 20179a502fSShawn Guo /* These register offsets are relative to LP (Low Power) range */ 21179a502fSShawn Guo #define SNVS_LPCR 0x04 22179a502fSShawn Guo #define SNVS_LPSR 0x18 23179a502fSShawn Guo #define SNVS_LPSRTCMR 0x1c 24179a502fSShawn Guo #define SNVS_LPSRTCLR 0x20 25179a502fSShawn Guo #define SNVS_LPTAR 0x24 26179a502fSShawn Guo #define SNVS_LPPGDR 0x30 27179a502fSShawn Guo 28179a502fSShawn Guo #define SNVS_LPCR_SRTC_ENV (1 << 0) 29179a502fSShawn Guo #define SNVS_LPCR_LPTA_EN (1 << 1) 30179a502fSShawn Guo #define SNVS_LPCR_LPWUI_EN (1 << 3) 31179a502fSShawn Guo #define SNVS_LPSR_LPTA (1 << 0) 32179a502fSShawn Guo 33179a502fSShawn Guo #define SNVS_LPPGDR_INIT 0x41736166 34179a502fSShawn Guo #define CNTR_TO_SECS_SH 15 35179a502fSShawn Guo 36179a502fSShawn Guo struct snvs_rtc_data { 37179a502fSShawn Guo struct rtc_device *rtc; 38d482893bSFrank Li struct regmap *regmap; 39d482893bSFrank Li int offset; 40179a502fSShawn Guo int irq; 417f899399SSanchayan Maity struct clk *clk; 42179a502fSShawn Guo }; 43179a502fSShawn Guo 44cd7f3a24STrent Piepho /* Read 64 bit timer register, which could be in inconsistent state */ 45cd7f3a24STrent Piepho static u64 rtc_read_lpsrt(struct snvs_rtc_data *data) 46cd7f3a24STrent Piepho { 47cd7f3a24STrent Piepho u32 msb, lsb; 48cd7f3a24STrent Piepho 49cd7f3a24STrent Piepho regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &msb); 50cd7f3a24STrent Piepho regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &lsb); 51cd7f3a24STrent Piepho return (u64)msb << 32 | lsb; 52cd7f3a24STrent Piepho } 53cd7f3a24STrent Piepho 54cd7f3a24STrent Piepho /* Read the secure real time counter, taking care to deal with the cases of the 55cd7f3a24STrent Piepho * counter updating while being read. 56cd7f3a24STrent Piepho */ 57d482893bSFrank Li static u32 rtc_read_lp_counter(struct snvs_rtc_data *data) 58179a502fSShawn Guo { 59179a502fSShawn Guo u64 read1, read2; 60cd7f3a24STrent Piepho unsigned int timeout = 100; 61179a502fSShawn Guo 62cd7f3a24STrent Piepho /* As expected, the registers might update between the read of the LSB 63cd7f3a24STrent Piepho * reg and the MSB reg. It's also possible that one register might be 64cd7f3a24STrent Piepho * in partially modified state as well. 65cd7f3a24STrent Piepho */ 66cd7f3a24STrent Piepho read1 = rtc_read_lpsrt(data); 67179a502fSShawn Guo do { 68cd7f3a24STrent Piepho read2 = read1; 69cd7f3a24STrent Piepho read1 = rtc_read_lpsrt(data); 70cd7f3a24STrent Piepho } while (read1 != read2 && --timeout); 71cd7f3a24STrent Piepho if (!timeout) 72cd7f3a24STrent Piepho dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); 73179a502fSShawn Guo 74179a502fSShawn Guo /* Convert 47-bit counter to 32-bit raw second count */ 75179a502fSShawn Guo return (u32) (read1 >> CNTR_TO_SECS_SH); 76179a502fSShawn Guo } 77179a502fSShawn Guo 78cd7f3a24STrent Piepho /* Just read the lsb from the counter, dealing with inconsistent state */ 79cd7f3a24STrent Piepho static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb) 80179a502fSShawn Guo { 81cd7f3a24STrent Piepho u32 count1, count2; 82cd7f3a24STrent Piepho unsigned int timeout = 100; 83179a502fSShawn Guo 84d482893bSFrank Li regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); 85179a502fSShawn Guo do { 86cd7f3a24STrent Piepho count2 = count1; 87cd7f3a24STrent Piepho regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); 88cd7f3a24STrent Piepho } while (count1 != count2 && --timeout); 89cd7f3a24STrent Piepho if (!timeout) { 90cd7f3a24STrent Piepho dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); 91cd7f3a24STrent Piepho return -ETIMEDOUT; 92179a502fSShawn Guo } 93cd7f3a24STrent Piepho 94cd7f3a24STrent Piepho *lsb = count1; 95cd7f3a24STrent Piepho return 0; 96cd7f3a24STrent Piepho } 97cd7f3a24STrent Piepho 98cd7f3a24STrent Piepho static int rtc_write_sync_lp(struct snvs_rtc_data *data) 99cd7f3a24STrent Piepho { 100cd7f3a24STrent Piepho u32 count1, count2; 101cd7f3a24STrent Piepho u32 elapsed; 102cd7f3a24STrent Piepho unsigned int timeout = 1000; 103cd7f3a24STrent Piepho int ret; 104cd7f3a24STrent Piepho 105cd7f3a24STrent Piepho ret = rtc_read_lp_counter_lsb(data, &count1); 106cd7f3a24STrent Piepho if (ret) 107cd7f3a24STrent Piepho return ret; 108cd7f3a24STrent Piepho 109cd7f3a24STrent Piepho /* Wait for 3 CKIL cycles, about 61.0-91.5 µs */ 110cd7f3a24STrent Piepho do { 111cd7f3a24STrent Piepho ret = rtc_read_lp_counter_lsb(data, &count2); 112cd7f3a24STrent Piepho if (ret) 113cd7f3a24STrent Piepho return ret; 114cd7f3a24STrent Piepho elapsed = count2 - count1; /* wrap around _is_ handled! */ 115cd7f3a24STrent Piepho } while (elapsed < 3 && --timeout); 116cd7f3a24STrent Piepho if (!timeout) { 117cd7f3a24STrent Piepho dev_err(&data->rtc->dev, "Timeout waiting for LPSRT Counter to change\n"); 118cd7f3a24STrent Piepho return -ETIMEDOUT; 119cd7f3a24STrent Piepho } 120cd7f3a24STrent Piepho return 0; 121179a502fSShawn Guo } 122179a502fSShawn Guo 123179a502fSShawn Guo static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) 124179a502fSShawn Guo { 125179a502fSShawn Guo int timeout = 1000; 126179a502fSShawn Guo u32 lpcr; 127179a502fSShawn Guo 128d482893bSFrank Li regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_SRTC_ENV, 129d482893bSFrank Li enable ? SNVS_LPCR_SRTC_ENV : 0); 130179a502fSShawn Guo 131179a502fSShawn Guo while (--timeout) { 132d482893bSFrank Li regmap_read(data->regmap, data->offset + SNVS_LPCR, &lpcr); 133179a502fSShawn Guo 134179a502fSShawn Guo if (enable) { 135179a502fSShawn Guo if (lpcr & SNVS_LPCR_SRTC_ENV) 136179a502fSShawn Guo break; 137179a502fSShawn Guo } else { 138179a502fSShawn Guo if (!(lpcr & SNVS_LPCR_SRTC_ENV)) 139179a502fSShawn Guo break; 140179a502fSShawn Guo } 141179a502fSShawn Guo } 142179a502fSShawn Guo 143179a502fSShawn Guo if (!timeout) 144179a502fSShawn Guo return -ETIMEDOUT; 145179a502fSShawn Guo 146179a502fSShawn Guo return 0; 147179a502fSShawn Guo } 148179a502fSShawn Guo 149179a502fSShawn Guo static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm) 150179a502fSShawn Guo { 151179a502fSShawn Guo struct snvs_rtc_data *data = dev_get_drvdata(dev); 152d482893bSFrank Li unsigned long time = rtc_read_lp_counter(data); 153179a502fSShawn Guo 154179a502fSShawn Guo rtc_time_to_tm(time, tm); 155179a502fSShawn Guo 156179a502fSShawn Guo return 0; 157179a502fSShawn Guo } 158179a502fSShawn Guo 159179a502fSShawn Guo static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm) 160179a502fSShawn Guo { 161179a502fSShawn Guo struct snvs_rtc_data *data = dev_get_drvdata(dev); 162179a502fSShawn Guo unsigned long time; 1631485991cSBryan O'Donoghue int ret; 164179a502fSShawn Guo 165179a502fSShawn Guo rtc_tm_to_time(tm, &time); 166179a502fSShawn Guo 167179a502fSShawn Guo /* Disable RTC first */ 1681485991cSBryan O'Donoghue ret = snvs_rtc_enable(data, false); 1691485991cSBryan O'Donoghue if (ret) 1701485991cSBryan O'Donoghue return ret; 171179a502fSShawn Guo 172179a502fSShawn Guo /* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */ 173d482893bSFrank Li regmap_write(data->regmap, data->offset + SNVS_LPSRTCLR, time << CNTR_TO_SECS_SH); 174d482893bSFrank Li regmap_write(data->regmap, data->offset + SNVS_LPSRTCMR, time >> (32 - CNTR_TO_SECS_SH)); 175179a502fSShawn Guo 176179a502fSShawn Guo /* Enable RTC again */ 1771485991cSBryan O'Donoghue ret = snvs_rtc_enable(data, true); 178179a502fSShawn Guo 1791485991cSBryan O'Donoghue return ret; 180179a502fSShawn Guo } 181179a502fSShawn Guo 182179a502fSShawn Guo static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 183179a502fSShawn Guo { 184179a502fSShawn Guo struct snvs_rtc_data *data = dev_get_drvdata(dev); 185179a502fSShawn Guo u32 lptar, lpsr; 186179a502fSShawn Guo 187d482893bSFrank Li regmap_read(data->regmap, data->offset + SNVS_LPTAR, &lptar); 188179a502fSShawn Guo rtc_time_to_tm(lptar, &alrm->time); 189179a502fSShawn Guo 190d482893bSFrank Li regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); 191179a502fSShawn Guo alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0; 192179a502fSShawn Guo 193179a502fSShawn Guo return 0; 194179a502fSShawn Guo } 195179a502fSShawn Guo 196179a502fSShawn Guo static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) 197179a502fSShawn Guo { 198179a502fSShawn Guo struct snvs_rtc_data *data = dev_get_drvdata(dev); 199179a502fSShawn Guo 200d482893bSFrank Li regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, 201d482893bSFrank Li (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN), 202d482893bSFrank Li enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0); 203179a502fSShawn Guo 204cd7f3a24STrent Piepho return rtc_write_sync_lp(data); 205179a502fSShawn Guo } 206179a502fSShawn Guo 207179a502fSShawn Guo static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 208179a502fSShawn Guo { 209179a502fSShawn Guo struct snvs_rtc_data *data = dev_get_drvdata(dev); 210179a502fSShawn Guo struct rtc_time *alrm_tm = &alrm->time; 211179a502fSShawn Guo unsigned long time; 212cd7f3a24STrent Piepho int ret; 213179a502fSShawn Guo 214179a502fSShawn Guo rtc_tm_to_time(alrm_tm, &time); 215179a502fSShawn Guo 216d482893bSFrank Li regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0); 217cd7f3a24STrent Piepho ret = rtc_write_sync_lp(data); 218cd7f3a24STrent Piepho if (ret) 219cd7f3a24STrent Piepho return ret; 220d482893bSFrank Li regmap_write(data->regmap, data->offset + SNVS_LPTAR, time); 221179a502fSShawn Guo 222179a502fSShawn Guo /* Clear alarm interrupt status bit */ 223d482893bSFrank Li regmap_write(data->regmap, data->offset + SNVS_LPSR, SNVS_LPSR_LPTA); 224179a502fSShawn Guo 225179a502fSShawn Guo return snvs_rtc_alarm_irq_enable(dev, alrm->enabled); 226179a502fSShawn Guo } 227179a502fSShawn Guo 228179a502fSShawn Guo static const struct rtc_class_ops snvs_rtc_ops = { 229179a502fSShawn Guo .read_time = snvs_rtc_read_time, 230179a502fSShawn Guo .set_time = snvs_rtc_set_time, 231179a502fSShawn Guo .read_alarm = snvs_rtc_read_alarm, 232179a502fSShawn Guo .set_alarm = snvs_rtc_set_alarm, 233179a502fSShawn Guo .alarm_irq_enable = snvs_rtc_alarm_irq_enable, 234179a502fSShawn Guo }; 235179a502fSShawn Guo 236179a502fSShawn Guo static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id) 237179a502fSShawn Guo { 238179a502fSShawn Guo struct device *dev = dev_id; 239179a502fSShawn Guo struct snvs_rtc_data *data = dev_get_drvdata(dev); 240179a502fSShawn Guo u32 lpsr; 241179a502fSShawn Guo u32 events = 0; 242179a502fSShawn Guo 243edb190cbSAnson Huang if (data->clk) 244edb190cbSAnson Huang clk_enable(data->clk); 245edb190cbSAnson Huang 246d482893bSFrank Li regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); 247179a502fSShawn Guo 248179a502fSShawn Guo if (lpsr & SNVS_LPSR_LPTA) { 249179a502fSShawn Guo events |= (RTC_AF | RTC_IRQF); 250179a502fSShawn Guo 251179a502fSShawn Guo /* RTC alarm should be one-shot */ 252179a502fSShawn Guo snvs_rtc_alarm_irq_enable(dev, 0); 253179a502fSShawn Guo 254179a502fSShawn Guo rtc_update_irq(data->rtc, 1, events); 255179a502fSShawn Guo } 256179a502fSShawn Guo 257179a502fSShawn Guo /* clear interrupt status */ 258d482893bSFrank Li regmap_write(data->regmap, data->offset + SNVS_LPSR, lpsr); 259179a502fSShawn Guo 260edb190cbSAnson Huang if (data->clk) 261edb190cbSAnson Huang clk_disable(data->clk); 262edb190cbSAnson Huang 263179a502fSShawn Guo return events ? IRQ_HANDLED : IRQ_NONE; 264179a502fSShawn Guo } 265179a502fSShawn Guo 266d482893bSFrank Li static const struct regmap_config snvs_rtc_config = { 267d482893bSFrank Li .reg_bits = 32, 268d482893bSFrank Li .val_bits = 32, 269d482893bSFrank Li .reg_stride = 4, 270d482893bSFrank Li }; 271d482893bSFrank Li 2725a167f45SGreg Kroah-Hartman static int snvs_rtc_probe(struct platform_device *pdev) 273179a502fSShawn Guo { 274179a502fSShawn Guo struct snvs_rtc_data *data; 275179a502fSShawn Guo struct resource *res; 276179a502fSShawn Guo int ret; 277d482893bSFrank Li void __iomem *mmio; 278179a502fSShawn Guo 279179a502fSShawn Guo data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 280179a502fSShawn Guo if (!data) 281179a502fSShawn Guo return -ENOMEM; 282179a502fSShawn Guo 283d482893bSFrank Li data->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap"); 284d482893bSFrank Li 285d482893bSFrank Li if (IS_ERR(data->regmap)) { 286d482893bSFrank Li dev_warn(&pdev->dev, "snvs rtc: you use old dts file, please update it\n"); 287179a502fSShawn Guo res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 288d482893bSFrank Li 289d482893bSFrank Li mmio = devm_ioremap_resource(&pdev->dev, res); 290d482893bSFrank Li if (IS_ERR(mmio)) 291d482893bSFrank Li return PTR_ERR(mmio); 292d482893bSFrank Li 293d482893bSFrank Li data->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, &snvs_rtc_config); 294d482893bSFrank Li } else { 295d482893bSFrank Li data->offset = SNVS_LPREGISTER_OFFSET; 296d482893bSFrank Li of_property_read_u32(pdev->dev.of_node, "offset", &data->offset); 297d482893bSFrank Li } 298d482893bSFrank Li 29975892900SPan Bian if (IS_ERR(data->regmap)) { 300d482893bSFrank Li dev_err(&pdev->dev, "Can't find snvs syscon\n"); 301d482893bSFrank Li return -ENODEV; 302d482893bSFrank Li } 303179a502fSShawn Guo 304179a502fSShawn Guo data->irq = platform_get_irq(pdev, 0); 305179a502fSShawn Guo if (data->irq < 0) 306179a502fSShawn Guo return data->irq; 307179a502fSShawn Guo 3087f899399SSanchayan Maity data->clk = devm_clk_get(&pdev->dev, "snvs-rtc"); 3097f899399SSanchayan Maity if (IS_ERR(data->clk)) { 3107f899399SSanchayan Maity data->clk = NULL; 3117f899399SSanchayan Maity } else { 3127f899399SSanchayan Maity ret = clk_prepare_enable(data->clk); 3137f899399SSanchayan Maity if (ret) { 3147f899399SSanchayan Maity dev_err(&pdev->dev, 3157f899399SSanchayan Maity "Could not prepare or enable the snvs clock\n"); 3167f899399SSanchayan Maity return ret; 3177f899399SSanchayan Maity } 3187f899399SSanchayan Maity } 3197f899399SSanchayan Maity 320179a502fSShawn Guo platform_set_drvdata(pdev, data); 321179a502fSShawn Guo 322179a502fSShawn Guo /* Initialize glitch detect */ 323d482893bSFrank Li regmap_write(data->regmap, data->offset + SNVS_LPPGDR, SNVS_LPPGDR_INIT); 324179a502fSShawn Guo 325179a502fSShawn Guo /* Clear interrupt status */ 326d482893bSFrank Li regmap_write(data->regmap, data->offset + SNVS_LPSR, 0xffffffff); 327179a502fSShawn Guo 328179a502fSShawn Guo /* Enable RTC */ 3291485991cSBryan O'Donoghue ret = snvs_rtc_enable(data, true); 3301485991cSBryan O'Donoghue if (ret) { 3311485991cSBryan O'Donoghue dev_err(&pdev->dev, "failed to enable rtc %d\n", ret); 3321485991cSBryan O'Donoghue goto error_rtc_device_register; 3331485991cSBryan O'Donoghue } 334179a502fSShawn Guo 335179a502fSShawn Guo device_init_wakeup(&pdev->dev, true); 336*e7afddb2SAnson Huang ret = dev_pm_set_wake_irq(&pdev->dev, data->irq); 337*e7afddb2SAnson Huang if (ret) 338*e7afddb2SAnson Huang dev_err(&pdev->dev, "failed to enable irq wake\n"); 339179a502fSShawn Guo 340179a502fSShawn Guo ret = devm_request_irq(&pdev->dev, data->irq, snvs_rtc_irq_handler, 341179a502fSShawn Guo IRQF_SHARED, "rtc alarm", &pdev->dev); 342179a502fSShawn Guo if (ret) { 343179a502fSShawn Guo dev_err(&pdev->dev, "failed to request irq %d: %d\n", 344179a502fSShawn Guo data->irq, ret); 3457f899399SSanchayan Maity goto error_rtc_device_register; 346179a502fSShawn Guo } 347179a502fSShawn Guo 348904784c1SJingoo Han data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, 349179a502fSShawn Guo &snvs_rtc_ops, THIS_MODULE); 350179a502fSShawn Guo if (IS_ERR(data->rtc)) { 351179a502fSShawn Guo ret = PTR_ERR(data->rtc); 352179a502fSShawn Guo dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); 3537f899399SSanchayan Maity goto error_rtc_device_register; 354179a502fSShawn Guo } 355179a502fSShawn Guo 356179a502fSShawn Guo return 0; 3577f899399SSanchayan Maity 3587f899399SSanchayan Maity error_rtc_device_register: 3597f899399SSanchayan Maity if (data->clk) 3607f899399SSanchayan Maity clk_disable_unprepare(data->clk); 3617f899399SSanchayan Maity 3627f899399SSanchayan Maity return ret; 363179a502fSShawn Guo } 364179a502fSShawn Guo 365179a502fSShawn Guo #ifdef CONFIG_PM_SLEEP 366119434f4SStefan Agner 367119434f4SStefan Agner static int snvs_rtc_suspend_noirq(struct device *dev) 368119434f4SStefan Agner { 369119434f4SStefan Agner struct snvs_rtc_data *data = dev_get_drvdata(dev); 370119434f4SStefan Agner 3717f899399SSanchayan Maity if (data->clk) 3727f899399SSanchayan Maity clk_disable_unprepare(data->clk); 3737f899399SSanchayan Maity 374179a502fSShawn Guo return 0; 375179a502fSShawn Guo } 376179a502fSShawn Guo 377119434f4SStefan Agner static int snvs_rtc_resume_noirq(struct device *dev) 378119434f4SStefan Agner { 379119434f4SStefan Agner struct snvs_rtc_data *data = dev_get_drvdata(dev); 380119434f4SStefan Agner 381119434f4SStefan Agner if (data->clk) 382119434f4SStefan Agner return clk_prepare_enable(data->clk); 383119434f4SStefan Agner 384179a502fSShawn Guo return 0; 385179a502fSShawn Guo } 386179a502fSShawn Guo 3877654e9d4SSanchayan Maity static const struct dev_pm_ops snvs_rtc_pm_ops = { 388119434f4SStefan Agner .suspend_noirq = snvs_rtc_suspend_noirq, 389119434f4SStefan Agner .resume_noirq = snvs_rtc_resume_noirq, 3907654e9d4SSanchayan Maity }; 391179a502fSShawn Guo 39288221c32SGuenter Roeck #define SNVS_RTC_PM_OPS (&snvs_rtc_pm_ops) 39388221c32SGuenter Roeck 39488221c32SGuenter Roeck #else 39588221c32SGuenter Roeck 39688221c32SGuenter Roeck #define SNVS_RTC_PM_OPS NULL 39788221c32SGuenter Roeck 39888221c32SGuenter Roeck #endif 39988221c32SGuenter Roeck 4005a167f45SGreg Kroah-Hartman static const struct of_device_id snvs_dt_ids[] = { 401179a502fSShawn Guo { .compatible = "fsl,sec-v4.0-mon-rtc-lp", }, 402179a502fSShawn Guo { /* sentinel */ } 403179a502fSShawn Guo }; 404179a502fSShawn Guo MODULE_DEVICE_TABLE(of, snvs_dt_ids); 405179a502fSShawn Guo 406179a502fSShawn Guo static struct platform_driver snvs_rtc_driver = { 407179a502fSShawn Guo .driver = { 408179a502fSShawn Guo .name = "snvs_rtc", 40988221c32SGuenter Roeck .pm = SNVS_RTC_PM_OPS, 410c39b3717SSachin Kamat .of_match_table = snvs_dt_ids, 411179a502fSShawn Guo }, 412179a502fSShawn Guo .probe = snvs_rtc_probe, 413179a502fSShawn Guo }; 414179a502fSShawn Guo module_platform_driver(snvs_rtc_driver); 415179a502fSShawn Guo 416179a502fSShawn Guo MODULE_AUTHOR("Freescale Semiconductor, Inc."); 417179a502fSShawn Guo MODULE_DESCRIPTION("Freescale SNVS RTC Driver"); 418179a502fSShawn Guo MODULE_LICENSE("GPL"); 419