/* * According to the datasheet, the OS should wait 5us after every * register write to the RTC hard macro so that the required update * can occur without holding off the system bus * According to errata RES-3124064, Write to any RTC register * may fail. As a workaround, before writing to RTC * register, issue a dummy write of 0x0 twice to RTC Status * register.
*/
static u32 read_rtc_register_38x_wa(struct armada38x_rtc *rtc, u8 rtc_reg)
{ int i, index_max = 0, max = 0;
for (i = 0; i < SAMPLE_NR; i++) {
rtc->val_to_freq[i].value = readl(rtc->regs + rtc_reg);
rtc->val_to_freq[i].freq = 0;
}
for (i = 0; i < SAMPLE_NR; i++) { int j = 0;
u32 value = rtc->val_to_freq[i].value;
while (rtc->val_to_freq[j].freq) { if (rtc->val_to_freq[j].value == value) {
rtc->val_to_freq[j].freq++; break;
}
j++;
}
if (!rtc->val_to_freq[j].freq) {
rtc->val_to_freq[j].value = value;
rtc->val_to_freq[j].freq = 1;
}
if (rtc->val_to_freq[j].freq > max) {
index_max = j;
max = rtc->val_to_freq[j].freq;
}
/* * If a value already has half of the sample this is the most * frequent one and we can stop the research right now
*/ if (max > SAMPLE_NR / 2) break;
}
rtc->data->clear_isr(rtc);
val = rtc->data->read_rtc_reg(rtc, reg_irq); /* disable all the interrupts for alarm*/
rtc_delayed_write(0, rtc, reg_irq); /* Ack the event */
rtc_delayed_write(1 << rtc->data->alarm, rtc, RTC_STATUS);
spin_unlock(&rtc->lock);
if (val & RTC_IRQ_FREQ_EN) { if (val & RTC_IRQ_FREQ_1HZ)
event |= RTC_UF; else
event |= RTC_PF;
}
rtc_update_irq(rtc->rtc_dev, 1, event);
return IRQ_HANDLED;
}
/* * The information given in the Armada 388 functional spec is complex. * They give two different formulas for calculating the offset value, * but when considering "Offset" as an 8-bit signed integer, they both * reduce down to (we shall rename "Offset" as "val" here): * * val = (f_ideal / f_measured - 1) / resolution where f_ideal = 32768 * * Converting to time, f = 1/t: * val = (t_measured / t_ideal - 1) / resolution where t_ideal = 1/32768 * * => t_measured / t_ideal = val * resolution + 1 * * "offset" in the RTC interface is defined as: * t = t0 * (1 + offset * 1e-9) * where t is the desired period, t0 is the measured period with a zero * offset, which is t_measured above. With t0 = t_measured and t = t_ideal, * offset = (t_ideal / t_measured - 1) / 1e-9 * * => t_ideal / t_measured = offset * 1e-9 + 1 * * so: * * offset * 1e-9 + 1 = 1 / (val * resolution + 1) * * We want "resolution" to be an integer, so resolution = R * 1e-9, giving * offset = 1e18 / (val * R + 1e9) - 1e9 * val = (1e18 / (offset + 1e9) - 1e9) / R * with a common transformation: * f(x) = 1e18 / (x + 1e9) - 1e9 * offset = f(val * R) * val = f(offset) / R * * Armada 38x supports two modes, fine mode (954ppb) and coarse mode (3815ppb).
*/ staticlong armada38x_ppb_convert(long ppb)
{ long div = ppb + 1000000000L;
return div_s64(1000000000000000000LL + div / 2, div) - 1000000000L;
}
staticint armada38x_rtc_read_offset(struct device *dev, long *offset)
{ struct armada38x_rtc *rtc = dev_get_drvdata(dev); unsignedlong ccr, flags; long ppb_cor;
ppb_cor = (ccr & RTC_CCR_MODE ? 3815 : 954) * (s8)ccr; /* ppb_cor + 1000000000L can never be zero */
*offset = armada38x_ppb_convert(ppb_cor);
return 0;
}
staticint armada38x_rtc_set_offset(struct device *dev, long offset)
{ struct armada38x_rtc *rtc = dev_get_drvdata(dev); unsignedlong ccr = 0; long ppb_cor, off;
/* * The maximum ppb_cor is -128 * 3815 .. 127 * 3815, but we * need to clamp the input. This equates to -484270 .. 488558. * Not only is this to stop out of range "off" but also to * avoid the division by zero in armada38x_ppb_convert().
*/
offset = clamp(offset, -484270L, 488558L);
ppb_cor = armada38x_ppb_convert(offset);
/* * Use low update mode where possible, which gives a better * resolution of correction.
*/
off = DIV_ROUND_CLOSEST(ppb_cor, 954); if (off > 127 || off < -128) {
ccr = RTC_CCR_MODE;
off = DIV_ROUND_CLOSEST(ppb_cor, 3815);
}
/* * Armada 388 requires a bit pattern in bits 14..8 depending on * the sign bit: { 0, ~S, S, S, S, S, S }
*/
ccr |= (off & 0x3fff) ^ 0x2000;
rtc_delayed_write(ccr, rtc, RTC_CCR);
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.