Fishwaldo opened a new pull request, #19889:
URL: https://github.com/apache/nuttx/pull/19889
## Summary
The NXP PCF8563 is a battery backed I2C clock at the fixed address 0x51,
common on
RISC-V and ARM boards, and NuttX had no driver for it. The nearest part in
the tree,
the PCF85263, has a different register map.
The driver follows the shape of the external I2C clocks already here,
`ds3231` and
`pcf85263`: board logic calls `pcf8563_rtc_initialize()` once the bus
exists, and the
chip then answers `up_rtc_getdatetime()` and `up_rtc_settime()` for the
system clock.
No lower half, no device node, nothing selected by default.
## Three deliberate behaviours
Each is a place where the obvious implementation would be wrong.
**A read fails while the chip says its time is untrustworthy.** The top bit
of the
seconds register means the oscillator has stopped since the time was last
set, so
every register after it holds whatever it stopped on. A read in that state
returns
`-ENODATA` rather than the contents: a caller told the time is unknown can
act on
that, one told a wrong time cannot. A flat backup cell and a clock that has
never
been set both arrive here.
**No century is read out of the month register.** Its top bit marks a century
rollover, but which value means which century is a convention that parts
disagree on.
The chip is treated as a clock for 2000 to 2099, the bit is written back
exactly as it
was read, and a date outside those years is refused rather than stored as
one that
would read back different. This is what the mainline Linux driver does, for
the same
reason.
**The counters stop across a write.** Otherwise a carry can land between the
seconds
being written and the minutes. They are restarted even when the write
failed, since
the alternative is leaving a clock that has stopped.
The alarm and countdown timer are not implemented. Their registers are
defined, since
knowing where they are is most of the work of adding them later.
## Testing
ESWIN EIC7700 EVB (EIC7700X, 4 x RV64GC), kernel build, chip on I2C0. The
consumer is
a board port being upstreamed separately; this PR adds no in-tree user.
The system clock is seeded from the chip at boot with no device node
involved:
```
nsh> date
Mon, Aug 17 13:22:12 2026
```
Setting and reading back works, and the clock is running:
```
nsh> date -s "Jun 15 10:30:00 2025"
nsh> date
Sun, Jun 15 10:30:01 2025
```
**The year refusal needed care to test, and the first two attempts proved
nothing.**
`date -s "... 2105"` is rejected by NSH's own parser, which accepts 1900 to
2100, so
the driver never sees it. Setting 1999 *appears* to succeed, because
`clock_settime()`
returns 0 unconditionally and never propagates the RTC's error, so the
system clock
moves while the chip refuses. Rebooting is what proves it: the chip still
held the
last in-range value, advanced by the real elapsed time.
```
nsh> date -s "Dec 31 23:59:00 1999" # accepted by NSH, refused by the
chip
nsh> date
Fri, Dec 31 23:59:01 1999 # the system clock moved
# ... reboot ...
nsh> date
Sun, Jun 15 10:32:38 2025 # the chip kept the in-range value
```
That `clock_settime()` behaviour is worth knowing generally: on any NuttX
system, an
out-of-range or failed RTC write is invisible to the caller.
Compiled both ways, since no in-tree configuration builds this file (see
below):
`sim:rpproxy` plus `I2C` and `RTC_PCF8563`, with `RTC_DRIVER` on and off,
both clean
with no warnings. `tools/checkpatch.sh` and `nxstyle` pass.
## Notes for reviewers
* **CI does not compile this file.** No board in the tree enables any
external I2C
RTC, so `ds3231`, `pcf85263`, `mcp794xx` and `rx8010` are uncompiled too.
A green
run says nothing about this code; the measurements above are the evidence.
* **No `/dev/rtc0`, deliberately.** An earlier version of this driver
provided a lower
half and registered one. I removed it: of 57 `rtc_initialize()` call sites
in the
tree, not one uses an external I2C chip as the lower half, so that would
have made
this driver the only one of its kind. Exposing an `up_rtc_*` chip as a
device node
looks like a framework question rather than something to special-case here.
* **No documentation.** None of the seven external RTC drivers in
`drivers/timers` has
a documentation page, and `rtc.rst` describes the framework and
arch-internal lower
halves only. The three surprising behaviours above are in the Kconfig
help, which is
where the sibling drivers put such things.
* **Quieter than its siblings.** Four `rtcerr` and one `rtcwarn`, and no
`rtcinfo` or
`rtc_dumptime()` tracing, where the other four carry ten or eleven
`rtcinfo` calls
each. That is deliberate: the facts worth reporting are bus failure,
unknown time
and a refused year. All of it compiles out unless `CONFIG_DEBUG_RTC_*` is
set, so the
driver is silent by default.
* **A pre-existing conflict this driver inherits.** `CONFIG_RTC_ARCH` and
any external
RTC driver cannot be enabled together: both define `volatile bool
g_rtc_enabled`, and
the link fails with `multiple definition of 'g_rtc_enabled'` (confirmed on
RISC-V
ELF). All five external RTC drivers do this identically, so it is not
introduced
here, and nothing in Kconfig prevents the combination. Happy to fix it
separately if
you would like it addressed.
* **A board whose only clock is external needs `up_rtc_initialize()`.**
`clock_initialize()` calls it whenever `CONFIG_RTC` is set, immediately
below its own
comment saying an external clock must be brought up after the system has
booted, so
such a board does not link without a stub.
`boards/arm/stm32u5/nucleo-u5a5zj-q`
carries one with a comment saying it should not be there. I have kept the
stub out of
this driver, matching `ds3231`, and put it in the board; the underlying
bug in
`clock_initialize()` deserves its own fix.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]