[PATCH 10/15] counter: rz-mtu3-cnt: cache function values
From: Cosmin Tanislav
Date: Mon Sep 14 2026 - 16:39:35 EST
If an MTU3 channel is used in a specific phase counting mode, when
disabling it and enabling it again, the user set mode is lost because
the timer mode register (TMDR1) is initialized to the default value.
Save the timer mode after setting it and restore it on enable.
Use the cached value to determine the function in
rz_mtu3_count_function_read_helper().
Avoid writing the TMDR1 register when the count is disabled to prevent
writing registers without actually owning the channel, as the busy check
inside ch->is_busy can race with PWM operations.
Since runtime PM is ensured to be resumed if the count is enabled, drop
the pm_runtime_get_sync() and pm_runtime_put() calls.
Signed-off-by: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@xxxxxxxxxxx>
---
drivers/counter/rz-mtu3-cnt.c | 34 +++++++++++++++-------------------
1 file changed, 15 insertions(+), 19 deletions(-)
diff --git a/drivers/counter/rz-mtu3-cnt.c b/drivers/counter/rz-mtu3-cnt.c
index 68025c6ed409..3e380f69cb45 100644
--- a/drivers/counter/rz-mtu3-cnt.c
+++ b/drivers/counter/rz-mtu3-cnt.c
@@ -77,6 +77,7 @@ struct rz_mtu3_cnt {
struct rz_mtu3_channel *ch;
u32 ceiling[RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS];
u32 count[RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS];
+ u8 timer_mode[RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS];
bool count_is_enabled[RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS];
};
@@ -217,17 +218,11 @@ static int rz_mtu3_count_write(struct counter_device *counter,
return 0;
}
-static int rz_mtu3_count_function_read_helper(struct rz_mtu3_channel *const ch,
- struct counter_device *const counter,
+static int rz_mtu3_count_function_read_helper(struct rz_mtu3_cnt *const priv,
+ int id,
enum counter_function *function)
{
- u8 timer_mode;
-
- pm_runtime_get_sync(counter->parent);
- timer_mode = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TMDR1);
- pm_runtime_put(counter->parent);
-
- switch (timer_mode & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) {
+ switch (priv->timer_mode[id]) {
case RZ_MTU3_TMDR1_PH_CNT_MODE_1:
*function = COUNTER_FUNCTION_QUADRATURE_X4;
return 0;
@@ -259,7 +254,7 @@ static int rz_mtu3_count_function_read(struct counter_device *counter,
if (ret)
return ret;
- ret = rz_mtu3_count_function_read_helper(ch, counter, function);
+ ret = rz_mtu3_count_function_read_helper(priv, count->id, function);
mutex_unlock(&priv->lock);
return ret;
@@ -298,9 +293,9 @@ static int rz_mtu3_count_function_write(struct counter_device *counter,
return -EINVAL;
}
- pm_runtime_get_sync(counter->parent);
- rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, timer_mode);
- pm_runtime_put(counter->parent);
+ if (priv->count_is_enabled[count->id])
+ rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, timer_mode);
+ priv->timer_mode[count->id] = timer_mode;
mutex_unlock(&priv->lock);
return 0;
@@ -393,8 +388,8 @@ static void rz_mtu3_32bit_cnt_setting(struct counter_device *counter)
struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1);
struct rz_mtu3_cnt *const priv = counter_priv(counter);
- /* Phase counting mode 1 is used as default in initialization. */
- rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_PH_CNT_MODE_1);
+ rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TMDR1,
+ priv->timer_mode[RZ_MTU3_32_BIT_CH]);
rz_mtu3_set_ceiling(ch1, RZ_MTU3_32_BIT_CH,
priv->ceiling[RZ_MTU3_32_BIT_CH]);
@@ -412,9 +407,7 @@ static void rz_mtu3_16bit_cnt_setting(struct counter_device *counter, int id)
struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id);
struct rz_mtu3_cnt *const priv = counter_priv(counter);
- /* Phase counting mode 1 is used as default in initialization. */
- rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_PH_CNT_MODE_1);
-
+ rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, priv->timer_mode[id]);
rz_mtu3_set_ceiling(ch, id, priv->ceiling[id]);
rz_mtu3_set_count(ch, id, priv->count[id]);
@@ -644,7 +637,7 @@ static int rz_mtu3_action_read(struct counter_device *counter,
if (ret)
return ret;
- ret = rz_mtu3_count_function_read_helper(ch, counter, &function);
+ ret = rz_mtu3_count_function_read_helper(priv, count->id, &function);
if (ret) {
mutex_unlock(&priv->lock);
return ret;
@@ -811,6 +804,7 @@ static int rz_mtu3_cnt_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct counter_device *counter;
struct rz_mtu3_cnt *priv;
+ unsigned int i;
int ret;
counter = devm_counter_alloc(dev, sizeof(*priv));
@@ -822,6 +816,8 @@ static int rz_mtu3_cnt_probe(struct platform_device *pdev)
priv->ceiling[RZ_MTU3_16_BIT_MTU2_CH] = U16_MAX;
priv->ceiling[RZ_MTU3_32_BIT_CH] = U32_MAX;
priv->ch = &ddata->channels[RZ_MTU3_CHAN_1];
+ for (i = 0; i < RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS; i++)
+ priv->timer_mode[i] = RZ_MTU3_TMDR1_PH_CNT_MODE_1;
mutex_init(&priv->lock);
--
2.55.0