/* Common bit definitions for Interrupt status and control registers */ #define RTC_BIT_AI (1 << 0) /* Alarm interrupt bit */ #define RTC_BIT_PI (1 << 1) /* Periodic interrupt bit. ST variants only. */
/* Common bit definations for ST v2 for reading/writing time */ #define RTC_SEC_SHIFT 0 #define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */ #define RTC_MIN_SHIFT 6 #define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */ #define RTC_HOUR_SHIFT 12 #define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */ #define RTC_WDAY_SHIFT 17 #define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */ #define RTC_MDAY_SHIFT 20 #define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */ #define RTC_MON_SHIFT 25 #define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */
#define RTC_TIMER_FREQ 32768
/** * struct pl031_vendor_data - per-vendor variations * @ops: the vendor-specific operations used on this silicon version * @clockwatch: if this is an ST Microelectronics silicon version with a * clockwatch function * @st_weekday: if this is an ST Microelectronics silicon version that need * the weekday fix * @irqflags: special IRQ flags per variant * @range_min: minimum date/time supported by the RTC * @range_max: maximum date/time supported by the RTC
*/ struct pl031_vendor_data { struct rtc_class_ops ops; bool clockwatch; bool st_weekday; unsignedlong irqflags;
time64_t range_min;
timeu64_t range_max;
};
/* * Convert Gregorian date to ST v2 RTC format.
*/ staticint pl031_stv2_tm_to_time(struct device *dev, struct rtc_time *tm, unsignedlong *st_time, unsignedlong *bcd_year)
{ int year = tm->tm_year + 1900; int wday = tm->tm_wday;
/* wday masking is not working in hardware so wday must be valid */ if (wday < -1 || wday > 6) {
dev_err(dev, "invalid wday value %d\n", tm->tm_wday); return -EINVAL;
} elseif (wday == -1) { /* wday is not provided, calculate it here */ struct rtc_time calc_tm;
data = readl(ldata->base + RTC_CR); /* Enable the clockwatch on ST Variants */ if (vendor->clockwatch)
data |= RTC_CR_CWEN; else
data |= RTC_CR_EN;
writel(data, ldata->base + RTC_CR);
/* * On ST PL031 variants, the RTC reset value does not provide correct * weekday for 2000-01-01. Correct the erroneous sunday to saturday.
*/ if (vendor->st_weekday) { if (readl(ldata->base + RTC_YDR) == 0x2000) {
time = readl(ldata->base + RTC_DR); if ((time &
(RTC_MON_MASK | RTC_MDAY_MASK | RTC_WDAY_MASK))
== 0x02120000) {
time = time | (0x7 << RTC_WDAY_SHIFT);
writel(0x2000, ldata->base + RTC_YLR);
writel(time, ldata->base + RTC_LR);
}
}
}
devm_device_init_wakeup(&adev->dev);
ldata->rtc = devm_rtc_allocate_device(&adev->dev); if (IS_ERR(ldata->rtc)) {
ret = PTR_ERR(ldata->rtc); goto out;
}
if (!adev->irq[0])
clear_bit(RTC_FEATURE_ALARM, ldata->rtc->features);
/* And the second ST derivative */ staticstruct pl031_vendor_data stv2_pl031 = {
.ops = {
.read_time = pl031_stv2_read_time,
.set_time = pl031_stv2_set_time,
.read_alarm = pl031_stv2_read_alarm,
.set_alarm = pl031_stv2_set_alarm,
.alarm_irq_enable = pl031_alarm_irq_enable,
},
.clockwatch = true,
.st_weekday = true, /* * This variant shares the IRQ with another block and must not * suspend that IRQ line. * TODO check if it shares with IRQF_NO_SUSPEND user, else we can * remove IRQF_COND_SUSPEND
*/
.irqflags = IRQF_SHARED | IRQF_COND_SUSPEND,
.range_min = RTC_TIMESTAMP_BEGIN_0000,
.range_max = RTC_TIMESTAMP_END_9999,
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.