Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/3] rtc: pcf2127: Add support for output clock and disable the pcf2131 100th counter
@ 2026-11-02 13:07 Herve Codina
  2026-11-02 13:07 ` [PATCH 1/3] dt-bindings: rtc: pcf2127: Add support for clkout clock Herve Codina
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Herve Codina @ 2026-11-02 13:07 UTC (permalink / raw)
  To: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-rtc, devicetree, linux-kernel, Thomas Petazzoni,
	Herve Codina

Hi,

PCF2127, PCF2129, PCA2129 and PCF2131 provide a configurable output
clock. The first two patches in this series add support for this output
clock.

The third patch of the series disables the 100th counter available in
the PCF2131. This counter is enabled by default in the hardware but
100th seconds are not used by the RTC subsystem. Fully disabling it
allows to save energy when the RTC is powered by its battery without
any functional changes.

Best regards,
Hervé

Herve Codina (3):
  dt-bindings: rtc: pcf2127: Add support for clkout clock
  rtc: pcf2127: Add support for the clkout clock
  rtc: pcf2127: Disable the 100th counter for PCF2131

 .../devicetree/bindings/rtc/nxp,pcf2127.yaml  |   6 +
 drivers/rtc/rtc-pcf2127.c                     | 201 ++++++++++++++++++
 2 files changed, 207 insertions(+)

-- 
2.56.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/3] dt-bindings: rtc: pcf2127: Add support for clkout clock
  2026-11-02 13:07 [PATCH 0/3] rtc: pcf2127: Add support for output clock and disable the pcf2131 100th counter Herve Codina
@ 2026-11-02 13:07 ` Herve Codina
  2026-11-02 19:32   ` Conor Dooley
  2026-11-02 13:07 ` [PATCH 2/3] rtc: pcf2127: Add support for the " Herve Codina
  2026-11-02 13:07 ` [PATCH 3/3] rtc: pcf2127: Disable the 100th counter for PCF2131 Herve Codina
  2 siblings, 1 reply; 7+ messages in thread
From: Herve Codina @ 2026-11-02 13:07 UTC (permalink / raw)
  To: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-rtc, devicetree, linux-kernel, Thomas Petazzoni,
	Herve Codina

PCF2127, PCF2129, PCF2131 and PCA2129 provide a configurable output
clock on their CLKOUT pins.

Add support for this clock considering those devices as clock
providers.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml
index 11fcf0ca1ae0..11c0bc04f304 100644
--- a/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml
+++ b/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml
@@ -27,6 +27,12 @@ properties:
   interrupts:
     maxItems: 1
 
+  "#clock-cells":
+    const: 0
+
+  clock-output-names:
+    maxItems: 1
+
   start-year: true
 
   reset-source: true
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/3] rtc: pcf2127: Add support for the clkout clock
  2026-11-02 13:07 [PATCH 0/3] rtc: pcf2127: Add support for output clock and disable the pcf2131 100th counter Herve Codina
  2026-11-02 13:07 ` [PATCH 1/3] dt-bindings: rtc: pcf2127: Add support for clkout clock Herve Codina
@ 2026-11-02 13:07 ` Herve Codina
  2026-11-02 13:13   ` sashiko-bot
  2026-11-02 13:07 ` [PATCH 3/3] rtc: pcf2127: Disable the 100th counter for PCF2131 Herve Codina
  2 siblings, 1 reply; 7+ messages in thread
From: Herve Codina @ 2026-11-02 13:07 UTC (permalink / raw)
  To: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-rtc, devicetree, linux-kernel, Thomas Petazzoni,
	Herve Codina

All devices handled by the pcf2127 driver (i.e. PCF2127, PCF2129,
PCA2129 and PCF2131) have support for an output clock available at their
CLKOUT pins.

The clock frequency can be configured from 1 Hz to 32768 Hz and the
clock can be fully disabled putting the CLKOUT pin in HiZ.

Add support for this clkout output clock.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 drivers/rtc/rtc-pcf2127.c | 186 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 186 insertions(+)

diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 49542cc53411..1bb84f72cf5f 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -17,6 +17,7 @@
  *             https://www.nxp.com/docs/en/data-sheet/PCF2131DS.pdf
  */
 
+#include <linux/clk-provider.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/bcd.h>
@@ -60,6 +61,8 @@
 /* CLKOUT control register */
 #define PCF2127_REG_CLKOUT		0x0f
 #define PCF2127_BIT_CLKOUT_OTPR			BIT(5)
+#define PCF2127_CLKOUT_COF			GENMASK(2, 0)
+#define PCF2127_CLKOUT_COF_HIZ			7
 /* Watchdog registers */
 #define PCF2127_REG_WD_CTL		0x10
 #define PCF2127_BIT_WD_CTL_TF0			BIT(0)
@@ -211,6 +214,11 @@ struct pcf2127 {
 	bool irq_enabled;
 	time64_t ts[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp values. */
 	bool ts_valid[PCF2127_MAX_TS_SUPPORTED];  /* Timestamp valid indication. */
+#ifdef CONFIG_COMMON_CLK
+	struct clk_hw clkout_hw;
+	u32 clkout_cof;
+	bool clkout_enabled;
+#endif
 };
 
 /*
@@ -626,6 +634,180 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
 	return devm_watchdog_register_device(dev, &pcf2127->wdd);
 }
 
+#ifdef CONFIG_COMMON_CLK
+#define clkout_hw_to_pcf2127(_hw) container_of(_hw, struct pcf2127, clkout_hw)
+
+/* Rates indexed by COF values */
+static int pcf2127_clkout_rates[] = {
+	32768,
+	16384,
+	8192,
+	4096,
+	2048,
+	1024,
+	1,
+	0, /* 0Hz (COF 0b111) will put the clockout signal to HiZ */
+};
+
+static u32 pcf2127_clkout_rate2cof(unsigned long rate)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(pcf2127_clkout_rates); i++) {
+		if (pcf2127_clkout_rates[i] <= rate)
+			return i;
+	}
+
+	return 0; /* Maximum output clock rate */
+}
+
+static int pcf2127_clkout_cof2rate(u32 cof)
+{
+	return pcf2127_clkout_rates[cof];
+}
+
+static unsigned long pcf2127_clkout_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	struct pcf2127 *pcf2127 = clkout_hw_to_pcf2127(hw);
+
+	return pcf2127_clkout_cof2rate(pcf2127->clkout_cof);
+}
+
+static int pcf2127_clkout_determine_rate(struct clk_hw *hw,
+					 struct clk_rate_request *req)
+{
+	u32 cof;
+
+	cof = pcf2127_clkout_rate2cof(req->rate);
+	req->rate = pcf2127_clkout_cof2rate(cof);
+
+	return 0;
+}
+
+static int pcf2127_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long parent_rate)
+{
+	struct pcf2127 *pcf2127 = clkout_hw_to_pcf2127(hw);
+	u32 cof;
+	int ret;
+
+	cof = pcf2127_clkout_rate2cof(rate);
+
+	/*
+	 * Setting COF will enable the clock (i.e. output not in HiZ anymore)
+	 * Perform the operation only if already enabled.
+	 * Otherwise, do nothing. The expected COF will be set on prepare()
+	 */
+	if (pcf2127->clkout_enabled) {
+		ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->reg_clkout,
+					 PCF2127_CLKOUT_COF,
+					 FIELD_PREP(PCF2127_CLKOUT_COF, cof));
+		if (ret)
+			return ret;
+	}
+
+	pcf2127->clkout_cof = cof;
+	return 0;
+}
+
+static int pcf2127_clkout_control(struct clk_hw *hw, bool enable)
+{
+	struct pcf2127 *pcf2127 = clkout_hw_to_pcf2127(hw);
+	u32 cof;
+	int ret;
+
+	cof = enable ? pcf2127->clkout_cof : PCF2127_CLKOUT_COF_HIZ;
+
+	ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->reg_clkout,
+				 PCF2127_CLKOUT_COF,
+				 FIELD_PREP(PCF2127_CLKOUT_COF, cof));
+	if (ret)
+		return ret;
+
+	pcf2127->clkout_enabled = enable;
+	return 0;
+}
+
+static int pcf2127_clkout_prepare(struct clk_hw *hw)
+{
+	return pcf2127_clkout_control(hw, true);
+}
+
+static void pcf2127_clkout_unprepare(struct clk_hw *hw)
+{
+	pcf2127_clkout_control(hw, false);
+}
+
+static int pcf2127_clkout_is_prepared(struct clk_hw *hw)
+{
+	struct pcf2127 *pcf2127 = clkout_hw_to_pcf2127(hw);
+
+	return pcf2127->clkout_enabled;
+}
+
+static const struct clk_ops pcf2127_clkout_ops = {
+	.prepare = pcf2127_clkout_prepare,
+	.unprepare = pcf2127_clkout_unprepare,
+	.is_prepared = pcf2127_clkout_is_prepared,
+	.recalc_rate = pcf2127_clkout_recalc_rate,
+	.determine_rate = pcf2127_clkout_determine_rate,
+	.set_rate = pcf2127_clkout_set_rate,
+};
+
+static int pcf2127_clkout_init(struct device *dev, struct pcf2127 *pcf2127)
+{
+	struct clk_init_data init = {};
+	const char *name;
+	u32 clkout;
+	int ret;
+
+	/*
+	 * Backward compatibility
+	 *
+	 * The output clock is enabled by default in the hardware.
+	 *
+	 * Handling this clock in a clock driver can lead to stop this clock if
+	 * it is unused. To avoid that and be backward compatible, use the clock
+	 * driver only if we have been told to.
+	 */
+	if (!device_property_present(dev, "#clock-cells"))
+		return 0;
+
+	/* optional override of the clockname */
+	ret = device_property_read_string(dev, "clock-output-names", &name);
+
+	init.name = ret ? "pcf2127-clkout" : name;
+	init.ops = &pcf2127_clkout_ops;
+	pcf2127->clkout_hw.init = &init;
+
+	/* Get the initial value for the COF field */
+	ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_clkout, &clkout);
+	if (ret)
+		return ret;
+
+	pcf2127->clkout_enabled = true;
+	pcf2127->clkout_cof = FIELD_GET(PCF2127_CLKOUT_COF, clkout);
+	if (pcf2127->clkout_cof == PCF2127_CLKOUT_COF_HIZ) {
+		pcf2127->clkout_enabled = false;
+		pcf2127->clkout_cof = 0; /* Maximum rate (32768Hz) */
+	}
+
+	/* register the clock */
+	ret = devm_clk_hw_register(dev, &pcf2127->clkout_hw);
+	if (ret)
+		return ret;
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+					   &pcf2127->clkout_hw);
+}
+#else
+static int pcf2127_clkout_init(struct device *dev, struct pcf2127 *pcf2127)
+{
+	return 0;
+}
+#endif
+
 /* Alarm */
 static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
@@ -1319,6 +1501,10 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
 
 	pcf2127_watchdog_init(dev, pcf2127);
 
+	ret = pcf2127_clkout_init(dev, pcf2127);
+	if (ret < 0)
+		return ret;
+
 	/*
 	 * Disable battery low/switch-over timestamp and interrupts.
 	 * Clear battery interrupt flags which can block new trigger events.
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] rtc: pcf2127: Disable the 100th counter for PCF2131
  2026-11-02 13:07 [PATCH 0/3] rtc: pcf2127: Add support for output clock and disable the pcf2131 100th counter Herve Codina
  2026-11-02 13:07 ` [PATCH 1/3] dt-bindings: rtc: pcf2127: Add support for clkout clock Herve Codina
  2026-11-02 13:07 ` [PATCH 2/3] rtc: pcf2127: Add support for the " Herve Codina
@ 2026-11-02 13:07 ` Herve Codina
  2 siblings, 0 replies; 7+ messages in thread
From: Herve Codina @ 2026-11-02 13:07 UTC (permalink / raw)
  To: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-rtc, devicetree, linux-kernel, Thomas Petazzoni,
	Herve Codina

The PCF2131 has a 100th counter. This counter is enabled by default but
100th seconds values are not used in the RTC subsystem.

In order to save energy when the PCF2131 is powered by its battery,
disable this counter.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 drivers/rtc/rtc-pcf2127.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 1bb84f72cf5f..d090e7d063c4 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -35,6 +35,7 @@
 #define PCF2127_REG_CTRL1		0x00
 #define PCF2127_BIT_CTRL1_POR_OVRD		BIT(3)
 #define PCF2127_BIT_CTRL1_TSF1			BIT(4)
+#define PCF2131_BIT_CTRL1_100TH_S_DIS		BIT(4) /* Replace PCF2127 TSF1 bit */
 #define PCF2127_BIT_CTRL1_STOP			BIT(5)
 /* Control register 2 */
 #define PCF2127_REG_CTRL2		0x01
@@ -1455,6 +1456,20 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
 		ret = devm_rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg);
 	}
 
+	/*
+	 * PCF2131 has a 100th seconds counter enabled by default. 100th seconds
+	 * are not used.
+	 *
+	 * In order to save energy when the RTC is powered by its battery, fully
+	 * disable this counter.
+	 */
+	if (pcf2127->cfg->type == PCF2131) {
+		ret = regmap_set_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
+				      PCF2131_BIT_CTRL1_100TH_S_DIS);
+		if (ret < 0)
+			return ret;
+	}
+
 	/*
 	 * The "Power-On Reset Override" facility prevents the RTC to do a reset
 	 * after power on. For normal operation the PORO must be disabled.
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/3] rtc: pcf2127: Add support for the clkout clock
  2026-11-02 13:07 ` [PATCH 2/3] rtc: pcf2127: Add support for the " Herve Codina
@ 2026-11-02 13:13   ` sashiko-bot
  2026-11-02 13:49     ` Herve Codina
  0 siblings, 1 reply; 7+ messages in thread
From: sashiko-bot @ 2026-11-02 13:13 UTC (permalink / raw)
  To: Herve Codina; +Cc: linux-rtc, devicetree, robh, conor+dt, Alexandre Belloni

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] rtc: pcf2127: rate 0 in pcf2127_clkout_rate2cof() sets COF to HiZ
--

commit fd3d38a37715a1ab67448b3adb80c6b0ee46a7e2
Author: Herve Codina <herve.codina@bootlin.com>

rtc: pcf2127: Add support for the clkout clock

This commit adds common clock framework support for the CLKOUT output clock
on PCF2127, PCF2129, PCA2129, and PCF2131 RTC devices, allowing configuration
of frequencies from 1 Hz to 32768 Hz and disabling the output into HiZ.

> diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
> index ff2023908f5a3..2c442770ebc52 100644
> --- a/drivers/rtc/rtc-pcf2127.c
> +++ b/drivers/rtc/rtc-pcf2127.c

[ ... ]

> @@ -626,6 +634,180 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
>  	return devm_watchdog_register_device(dev, &pcf2127->wdd);
>  }
>  
> +#ifdef CONFIG_COMMON_CLK
> +#define clkout_hw_to_pcf2127(_hw) container_of(_hw, struct pcf2127, clkout_hw)
> +
> +/* Rates indexed by COF values */
> +static int pcf2127_clkout_rates[] = {
> +	32768,
> +	16384,
> +	8192,
> +	4096,
> +	2048,
> +	1024,
> +	1,
> +	0, /* 0Hz (COF 0b111) will put the clockout signal to HiZ */
> +};
> +
> +static u32 pcf2127_clkout_rate2cof(unsigned long rate)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(pcf2127_clkout_rates); i++) {
> +		if (pcf2127_clkout_rates[i] <= rate)
> +			return i;
> +	}
> +
> +	return 0; /* Maximum output clock rate */
> +}
> +
> +static int pcf2127_clkout_cof2rate(u32 cof)
> +{
> +	return pcf2127_clkout_rates[cof];
> +}
> +
> +static unsigned long pcf2127_clkout_recalc_rate(struct clk_hw *hw,
> +						unsigned long parent_rate)
> +{
> +	struct pcf2127 *pcf2127 = clkout_hw_to_pcf2127(hw);
> +
> +	return pcf2127_clkout_cof2rate(pcf2127->clkout_cof);
> +}
> +
> +static int pcf2127_clkout_determine_rate(struct clk_hw *hw,
> +					 struct clk_rate_request *req)
> +{
> +	u32 cof;
> +
> +	cof = pcf2127_clkout_rate2cof(req->rate);
> +	req->rate = pcf2127_clkout_cof2rate(cof);
> +
> +	return 0;
> +}
> +
> +static int pcf2127_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
> +				   unsigned long parent_rate)
> +{
> +	struct pcf2127 *pcf2127 = clkout_hw_to_pcf2127(hw);
> +	u32 cof;
> +	int ret;
> +
> +	cof = pcf2127_clkout_rate2cof(rate);
> +
> +	/*
> +	 * Setting COF will enable the clock (i.e. output not in HiZ anymore)
> +	 * Perform the operation only if already enabled.
> +	 * Otherwise, do nothing. The expected COF will be set on prepare()
> +	 */
> +	if (pcf2127->clkout_enabled) {
> +		ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->reg_clkout,
> +					 PCF2127_CLKOUT_COF,
> +					 FIELD_PREP(PCF2127_CLKOUT_COF, cof));
> +		if (ret)
> +			return ret;
> +	}
> +
> +	pcf2127->clkout_cof = cof;
> +	return 0;
> +}

[Severity: Medium]
Since rate is an unsigned long and pcf2127_clkout_rates[7] is 0, the condition
pcf2127_clkout_rates[i] <= rate in pcf2127_clkout_rate2cof() will always match
at index 7 (PCF2127_CLKOUT_COF_HIZ) when rate is 0, making the fallback
return 0 unreachable.

If a consumer passes rate == 0 to pcf2127_clkout_determine_rate() or
pcf2127_clkout_set_rate(), pcf2127_clkout_rate2cof(0) returns 7
(PCF2127_CLKOUT_COF_HIZ). In pcf2127_clkout_set_rate(), this writes
PCF2127_CLKOUT_COF_HIZ to reg_clkout if pcf2127->clkout_enabled is true
(putting the CLKOUT pin into HiZ while pcf2127->clkout_enabled remains true),
and caches PCF2127_CLKOUT_COF_HIZ in pcf2127->clkout_cof so subsequent calls
to pcf2127_clkout_prepare() -> pcf2127_clkout_control(hw, true) will also
leave the pin in HiZ.

Should the 0 entry be removed from pcf2127_clkout_rates[] (or skipped in
pcf2127_clkout_rate2cof()) so that pcf2127->clkout_cof only ever holds active
clock divider values (0..6)?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102130712.25104-1-herve.codina@bootlin.com?part=2

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/3] rtc: pcf2127: Add support for the clkout clock
  2026-11-02 13:13   ` sashiko-bot
@ 2026-11-02 13:49     ` Herve Codina
  0 siblings, 0 replies; 7+ messages in thread
From: Herve Codina @ 2026-11-02 13:49 UTC (permalink / raw)
  To: sashiko-bot
  Cc: sashiko-reviews, linux-rtc, devicetree, robh, conor+dt,
	Alexandre Belloni

On Mon, 02 Nov 2026 13:13:46 +0000
sashiko-bot@kernel.org wrote:

> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] rtc: pcf2127: rate 0 in pcf2127_clkout_rate2cof() sets COF to HiZ
> --
> 
> commit fd3d38a37715a1ab67448b3adb80c6b0ee46a7e2
> Author: Herve Codina <herve.codina@bootlin.com>
> 
> rtc: pcf2127: Add support for the clkout clock
> 
> This commit adds common clock framework support for the CLKOUT output clock
> on PCF2127, PCF2129, PCA2129, and PCF2131 RTC devices, allowing configuration
> of frequencies from 1 Hz to 32768 Hz and disabling the output into HiZ.
> 
> > diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
> > index ff2023908f5a3..2c442770ebc52 100644
> > --- a/drivers/rtc/rtc-pcf2127.c
> > +++ b/drivers/rtc/rtc-pcf2127.c  
> 
> [ ... ]
> 
> > @@ -626,6 +634,180 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
> >  	return devm_watchdog_register_device(dev, &pcf2127->wdd);
> >  }
> >  
> > +#ifdef CONFIG_COMMON_CLK
> > +#define clkout_hw_to_pcf2127(_hw) container_of(_hw, struct pcf2127, clkout_hw)
> > +
> > +/* Rates indexed by COF values */
> > +static int pcf2127_clkout_rates[] = {
> > +	32768,
> > +	16384,
> > +	8192,
> > +	4096,
> > +	2048,
> > +	1024,
> > +	1,
> > +	0, /* 0Hz (COF 0b111) will put the clockout signal to HiZ */
> > +};
> > +
> > +static u32 pcf2127_clkout_rate2cof(unsigned long rate)
> > +{
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(pcf2127_clkout_rates); i++) {
> > +		if (pcf2127_clkout_rates[i] <= rate)
> > +			return i;
> > +	}
> > +
> > +	return 0; /* Maximum output clock rate */
> > +}
> > +
> > +static int pcf2127_clkout_cof2rate(u32 cof)
> > +{
> > +	return pcf2127_clkout_rates[cof];
> > +}
> > +
> > +static unsigned long pcf2127_clkout_recalc_rate(struct clk_hw *hw,
> > +						unsigned long parent_rate)
> > +{
> > +	struct pcf2127 *pcf2127 = clkout_hw_to_pcf2127(hw);
> > +
> > +	return pcf2127_clkout_cof2rate(pcf2127->clkout_cof);
> > +}
> > +
> > +static int pcf2127_clkout_determine_rate(struct clk_hw *hw,
> > +					 struct clk_rate_request *req)
> > +{
> > +	u32 cof;
> > +
> > +	cof = pcf2127_clkout_rate2cof(req->rate);
> > +	req->rate = pcf2127_clkout_cof2rate(cof);
> > +
> > +	return 0;
> > +}
> > +
> > +static int pcf2127_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
> > +				   unsigned long parent_rate)
> > +{
> > +	struct pcf2127 *pcf2127 = clkout_hw_to_pcf2127(hw);
> > +	u32 cof;
> > +	int ret;
> > +
> > +	cof = pcf2127_clkout_rate2cof(rate);
> > +
> > +	/*
> > +	 * Setting COF will enable the clock (i.e. output not in HiZ anymore)
> > +	 * Perform the operation only if already enabled.
> > +	 * Otherwise, do nothing. The expected COF will be set on prepare()
> > +	 */
> > +	if (pcf2127->clkout_enabled) {
> > +		ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->reg_clkout,
> > +					 PCF2127_CLKOUT_COF,
> > +					 FIELD_PREP(PCF2127_CLKOUT_COF, cof));
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	pcf2127->clkout_cof = cof;
> > +	return 0;
> > +}  
> 
> [Severity: Medium]
> Since rate is an unsigned long and pcf2127_clkout_rates[7] is 0, the condition
> pcf2127_clkout_rates[i] <= rate in pcf2127_clkout_rate2cof() will always match
> at index 7 (PCF2127_CLKOUT_COF_HIZ) when rate is 0, making the fallback
> return 0 unreachable.
> 
> If a consumer passes rate == 0 to pcf2127_clkout_determine_rate() or
> pcf2127_clkout_set_rate(), pcf2127_clkout_rate2cof(0) returns 7
> (PCF2127_CLKOUT_COF_HIZ). In pcf2127_clkout_set_rate(), this writes
> PCF2127_CLKOUT_COF_HIZ to reg_clkout if pcf2127->clkout_enabled is true
> (putting the CLKOUT pin into HiZ while pcf2127->clkout_enabled remains true),
> and caches PCF2127_CLKOUT_COF_HIZ in pcf2127->clkout_cof so subsequent calls
> to pcf2127_clkout_prepare() -> pcf2127_clkout_control(hw, true) will also
> leave the pin in HiZ.

This is exactly what it is expected.

return 0 is unreachable but pcf2127_clkout_rate2cof() returns a u32.

Without the last return 0 (even if unreachable) or any other u32 returned value,
GCC obviously complied
   error: control reaches end of non-void function

> 
> Should the 0 entry be removed from pcf2127_clkout_rates[] (or skipped in
> pcf2127_clkout_rate2cof()) so that pcf2127->clkout_cof only ever holds active
> clock divider values (0..6)?
> 

No.

All rates should be present in pcf2127_clkout_rates[]. The 0Hz rate value is
a valid rate even if the pin will be set in HiZ in that case.

pcf2127->clkout_cof should hold the value related to OHz rate.

A user can ask a 0Hz rate and call clk_prepare(). This is a valid use case.

Best regards,
Hervé

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] dt-bindings: rtc: pcf2127: Add support for clkout clock
  2026-11-02 13:07 ` [PATCH 1/3] dt-bindings: rtc: pcf2127: Add support for clkout clock Herve Codina
@ 2026-11-02 19:32   ` Conor Dooley
  0 siblings, 0 replies; 7+ messages in thread
From: Conor Dooley @ 2026-11-02 19:32 UTC (permalink / raw)
  To: Herve Codina
  Cc: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-rtc, devicetree, linux-kernel, Thomas Petazzoni

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-11-02 19:32 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02 13:07 [PATCH 0/3] rtc: pcf2127: Add support for output clock and disable the pcf2131 100th counter Herve Codina
2026-11-02 13:07 ` [PATCH 1/3] dt-bindings: rtc: pcf2127: Add support for clkout clock Herve Codina
2026-11-02 19:32   ` Conor Dooley
2026-11-02 13:07 ` [PATCH 2/3] rtc: pcf2127: Add support for the " Herve Codina
2026-11-02 13:13   ` sashiko-bot
2026-11-02 13:49     ` Herve Codina
2026-11-02 13:07 ` [PATCH 3/3] rtc: pcf2127: Disable the 100th counter for PCF2131 Herve Codina

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox