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]

Reply via email to