[PATCH 1/3] mfd: rz-mtu3: do not use struct rz_mtu3_channel::dev

From: Cosmin Tanislav

Date: Mon Sep 14 2026 - 16:19:20 EST


Channels 1 and 2 are used by both the PWM and counter drivers. Both
subdrivers assign struct rz_mtu3_channel::dev to their own device
instance for those shared channels, so the value stored in it depends on
which subdriver binds last.

The MFD core helpers currently use ch->dev->parent to retrieve the
parent driver data, which makes them depend on subdriver-populated
state.

This is fragile for shared channels and unnecessarily couples the core
to child driver initialization.

Introduce a rz_mtu3_ch_to_priv() helper that takes in a pointer to a
struct rz_mtu3_channel and returns a pointer to the struct rz_mtu3_priv.

This is possible because the struct rz_mtu3_channel contains its index
(channel_number) in the struct rz_mtu3's channels array, allowing us to
retrieve the pointer of the first channel, and then its container.

By doing this, we remove the dependency on subdriver assigned data from
the parent driver.

Keep struct rz_mtu3_channel::dev for now, as it is still used by the PWM
and counter drivers.

Signed-off-by: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@xxxxxxxxxxx>
---
drivers/mfd/rz-mtu3.c | 41 +++++++++++++++++++----------------------
1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/drivers/mfd/rz-mtu3.c b/drivers/mfd/rz-mtu3.c
index 0a254e61ec0a..d809436e2124 100644
--- a/drivers/mfd/rz-mtu3.c
+++ b/drivers/mfd/rz-mtu3.c
@@ -60,10 +60,17 @@ static bool rz_mtu3_is_16bit_shared_reg(u16 offset)
offset == RZ_MTU3_TCNTSA || offset == RZ_MTU3_TCNTSB);
}

+static inline struct rz_mtu3_priv *rz_mtu3_ch_to_priv(struct rz_mtu3_channel *ch)
+{
+ struct rz_mtu3_channel *first_ch = ch - ch->channel_number;
+ struct rz_mtu3 *mtu = container_of(first_ch, struct rz_mtu3, channels[0]);
+
+ return mtu->priv_data;
+}
+
u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 offset)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);

if (rz_mtu3_is_16bit_shared_reg(offset))
return readw(priv->mmio + offset);
@@ -74,8 +81,7 @@ EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_read);

u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);
u16 ch_offs;

ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset];
@@ -86,8 +92,7 @@ EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_read);

u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);
u16 ch_offs;

/* MTU8 doesn't have 16-bit registers */
@@ -102,8 +107,7 @@ EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_read);

u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);
u16 ch_offs;

if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8)
@@ -117,8 +121,7 @@ EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_read);

void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u8 val)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);
u16 ch_offs;

ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset];
@@ -128,8 +131,7 @@ EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_write);

void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u16 val)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);
u16 ch_offs;

/* MTU8 doesn't have 16-bit registers */
@@ -143,8 +145,7 @@ EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_write);

void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u32 val)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);
u16 ch_offs;

if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8)
@@ -157,8 +158,7 @@ EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_write);

void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 offset, u16 value)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);

if (rz_mtu3_is_16bit_shared_reg(offset))
writew(value, priv->mmio + offset);
@@ -170,8 +170,7 @@ EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_write);
void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, u16 offset,
u16 pos, u8 val)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);
unsigned long tmdr, flags;

spin_lock_irqsave(&priv->lock, flags);
@@ -244,8 +243,7 @@ static u8 rz_mtu3_get_tstr_bit_pos(struct rz_mtu3_channel *ch)

static void rz_mtu3_start_stop_ch(struct rz_mtu3_channel *ch, bool start)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);
unsigned long flags, tstr;
u16 offset;
u8 bitpos;
@@ -265,8 +263,7 @@ static void rz_mtu3_start_stop_ch(struct rz_mtu3_channel *ch, bool start)

bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch)
{
- struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
- struct rz_mtu3_priv *priv = mtu->priv_data;
+ struct rz_mtu3_priv *priv = rz_mtu3_ch_to_priv(ch);
unsigned long flags, tstr;
u16 offset;
u8 bitpos;
--
2.55.0