Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2008 * Gururaja Hebbar gururajakr@sanyo.co.in * * reference linux-2.6.20.6/drivers/rtc/rtc-pl031.c */ #include <command.h> #include <dm.h> #include <errno.h> #include <log.h> #include <rtc.h> #include <asm/io.h> #include <asm/types.h> /* * Register definitions */ #define RTC_DR 0x00 /* Data read register */ #define RTC_MR 0x04 /* Match register */ #define RTC_LR 0x08 /* Data load register */ #define RTC_CR 0x0c /* Control register */ #define RTC_IMSC 0x10 /* Interrupt mask and set register */ #define RTC_RIS 0x14 /* Raw interrupt status register */ #define RTC_MIS 0x18 /* Masked interrupt status register */ #define RTC_ICR 0x1c /* Interrupt clear register */ #define RTC_CR_START (1 << 0) struct pl031_plat { phys_addr_t base; }; static inline u32 pl031_read_reg(struct udevice *dev, int reg) { struct pl031_plat *pdata = dev_get_plat(dev); return readl(pdata->base + reg); } static inline u32 pl031_write_reg(struct udevice *dev, int reg, u32 value) { struct pl031_plat *pdata = dev_get_plat(dev); return writel(value, pdata->base + reg); } /* * Probe RTC device */ static int pl031_probe(struct udevice *dev) { /* Enable RTC Start in Control register*/ pl031_write_reg(dev, RTC_CR, RTC_CR_START); return 0; } /* * Get the current time from the RTC */ static int pl031_get(struct udevice *dev, struct rtc_time *tm) { unsigned long tim; if (!tm) return -EINVAL; tim = pl031_read_reg(dev, RTC_DR); rtc_to_tm(tim, tm); debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); return 0; } /* * Set the RTC */ static int pl031_set(struct udevice *dev, const struct rtc_time *tm) { unsigned long tim; if (!tm) return -EINVAL; debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); /* Calculate number of seconds this incoming time represents */ tim = rtc_mktime(tm); pl031_write_reg(dev, RTC_LR, tim); return 0; } /* * Reset the RTC. We set the date back to 1970-01-01. */ static int pl031_reset(struct udevice *dev) { pl031_write_reg(dev, RTC_LR, 0); return 0; } static const struct rtc_ops pl031_ops = { .get = pl031_get, .set = pl031_set, .reset = pl031_reset, }; static const struct udevice_id pl031_ids[] = { { .compatible = "arm,pl031" }, { } }; static int pl031_of_to_plat(struct udevice *dev) { struct pl031_plat *pdata = dev_get_plat(dev); pdata->base = dev_read_addr(dev); return 0; } U_BOOT_DRIVER(rtc_pl031) = { .name = "rtc-pl031", .id = UCLASS_RTC, .of_match = pl031_ids, .probe = pl031_probe, .of_to_plat = pl031_of_to_plat, .plat_auto = sizeof(struct pl031_plat), .ops = &pl031_ops, }; |