| Message ID | 20260719153122.892013-1-juanmanuellopezcarrillo@gmail.com (mailing list archive) |
|---|---|
| State | New |
| Headers |
Return-Path: <linux-sunxi+bounces-24528-sunxi=pue.re@lists.linux.dev>
X-Original-To: noreply@patchwork.local
Delivered-To: noreply@patchwork.local
Received: from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10])
by mxe881.netcup.net (Postfix) with ESMTPS id C0AD11C2C23
for <noreply@patchwork.local>; Sun, 19 Jul 2026 17:32:03 +0200 (CEST)
Authentication-Results: mxe881;
dkim=pass header.d=gmail.com;
spf=pass (sender IP is 172.234.253.10)
smtp.mailfrom=linux-sunxi+bounces-24528-noreply=patchwork.local@lists.linux.dev
smtp.helo=sea.lore.kernel.org
Received-SPF: pass (mxe881: domain of lists.linux.dev designates
172.234.253.10 as permitted sender) client-ip=172.234.253.10;
envelope-from=linux-sunxi+bounces-24528-noreply=patchwork.local@lists.linux.dev;
helo=sea.lore.kernel.org;
Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org
[100.90.174.1])
by sea.lore.kernel.org (Postfix) with ESMTP id 942E63011C7A
for <noreply@patchwork.local>; Sun, 19 Jul 2026 15:31:46 +0000 (UTC)
Received: from localhost.localdomain (localhost.localdomain [127.0.0.1])
by smtp.subspace.kernel.org (Postfix) with ESMTP id 3B1C7392C56;
Sun, 19 Jul 2026 15:31:46 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org;
dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com
header.b="TMmuAFkg"
X-Original-To: linux-sunxi@lists.linux.dev
Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com
[209.85.128.45])
(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))
(No client certificate requested)
by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C7C443F08E
for <linux-sunxi@lists.linux.dev>; Sun, 19 Jul 2026 15:31:44 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org;
arc=none smtp.client-ip=209.85.128.45
ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;
t=1784475106; cv=none;
b=hzojRRPWS4GqlM0jSmSRmpHy0/aoHRyBnSTVCVRxcqZmtEoeTq+qwYkv/do4YmKRE08xEFb53cFKyLN3AfjzbzSiI54WCaadI2bNf8cD4YBPfMRs6+4NXCOFdT3rmd0BNg9Y1H0vHTUqhbRpT6F6APEjnqpa/NRLqUrFy79u6vI=
ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org;
s=arc-20240116; t=1784475106; c=relaxed/simple;
bh=7rKizl1VwNt3GDPCkBsLZAl45i1jv9HwynJC+jxYgbk=;
h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type;
b=BIcb2zBezLw7om2iCET3bzJN8JMlFoaotijQFEWRsOcfSDxnh0T8RgbI5kw3MdJkxZmu5vE+gyS7ykI4acTSFV8fXcfcvCQAll9pTm5czn/UqS4xaLpA38wI3zbFWvx1fMwEr1o5631Ap1k9Nx3W8p3A4bwtjsVKrCW9oxYpiGY=
ARC-Authentication-Results: i=1; smtp.subspace.kernel.org;
dmarc=pass (p=none dis=none) header.from=gmail.com;
spf=pass smtp.mailfrom=gmail.com;
dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com
header.b=TMmuAFkg; arc=none smtp.client-ip=209.85.128.45
Authentication-Results: smtp.subspace.kernel.org;
dmarc=pass (p=none dis=none) header.from=gmail.com
Authentication-Results: smtp.subspace.kernel.org;
spf=pass smtp.mailfrom=gmail.com
Received: by mail-wm1-f45.google.com with SMTP id
5b1f17b1804b1-4953e04ef16so35629835e9.2
for <linux-sunxi@lists.linux.dev>;
Sun, 19 Jul 2026 08:31:44 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20251104; t=1784475103; x=1785079903;
darn=lists.linux.dev;
h=content-transfer-encoding:content-type:mime-version:message-id:date
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to
:content-type;
bh=RAIvFoHSot582y5nPwOQ/4JfZFN3JPm5c7b4D+Z0OhU=;
b=TMmuAFkgs8HL/v4NczMOfgJMR4bHEE7N3rtXdel3ccxSyqMaUUhIpDU8R1PriOCUci
vrXdXKuxWg0Lsjv0iUhydpxm9a7Ki9slqlmgRGR8ZRAwVst/h2lm1eQKlNwhJAzutmVC
f2Jjq+Dj0n2bJdZnvgg+/6AQuxchrTswYHLphGyKsdSyeAmshfJF3IbMDXSwFBH6LvIn
Qe0xHS6rdeKRDl1DejZ2pkKvDWWuY8cXYoO+5KlhItenFPyy9Hvh0sTBatlH+15cdwTt
MeWKgalbrnkIRAVJ7Iqzx0bsKnrzpE3Pe83DZSHvN5smzPKlbcSGo/pMCJLBLMNWn3cB
7lWQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20251104; t=1784475103; x=1785079903;
h=content-transfer-encoding:content-type:mime-version:message-id:date
:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject
:date:message-id:reply-to:content-type;
bh=RAIvFoHSot582y5nPwOQ/4JfZFN3JPm5c7b4D+Z0OhU=;
b=bqpmcDOezVvwBHfcpYh7oAWqegmiLLHMicwdPRnB/zBAO2mokuo9mUr0PlykQeAAVe
HZMUrmnYH6PiU3DRvbYs+xO1+N9yX+CFjPe2jxA5UvzOTplGxPoMLWq00a1or5ps0Ixh
OSuVTYoDadMypfk2nB0iLIZ6Prv2NSO3eUpqmSCY4TWXGn29VGGyzJNwKGuRS8PbD1DW
mVq/N7C4D5g2ntV0cStP0I/Aj65745WhmudbyFvnTr48wdbWdhO7MCrsCwhIF235l/iZ
daOt4n7QMbAHS6RAnj81pNKzX9u9M0BM5heZ2NftEMfEbp76szCVJ8oLgpyxa18w4E6Q
sz9Q==
X-Forwarded-Encrypted: i=1;
AHgh+Rqw/6GZjOzGOzbBuQGgey+TWlBqb5LRmbUO95hsB2QM5tGNOsZooN+xC6j/8Ev7lKvjcksrruGRD1aI2g==@lists.linux.dev
X-Gm-Message-State: AOJu0Yzy8a6KGxFf1KVRbri+1GaWye9MHYGrJOyl/YJmd3OteaEo35P0
8VCQFmlAnDbPWEIH6EzflVQNTpb+XGBi08Mz4W2MO+bJKhSq68TjlSXm
X-Gm-Gg: AfdE7cn21qGBYUi2ESAVjrzSmQ56MxN3cI4/g4NZWfF8eO3SDUwNPDhBqhVN4fRyD1s
hH9wnEp4zc0ecnXtvbatV/P9cjkT6hi4lJsQyDpvkbGE+AEjxVHZ8Nqd4BV6QO3XOGimbhxzDBd
SrzWCPgiLgERHe3K/e6OKJiqZzpBRAumT9vaUpTlQKIOyTX3ZnTJhLJUD/19dnJY+etk+aRDLhX
AJt5gvrZmpLd/RQXNxwv8IUWQ7osgTJswPKk7AUeT/c/F+XYMaaVfAznOGyMipOWrQTGJEsxu6L
Xyu3POnoYgTgSzLKfB0BPe5Z/N/vEAZa267UmQpshLtkBvprCpZ2/GwdTVl4T5NrxZB0b809wa3
isiyd1EOOPAw31izA0MGrlSgUWc93daA4OyrVjZFgLnql/3MgXqXk761gKnjlB0dGIWoeejwvYk
UyKpKAeLK+f+dduQJ71wp5lKZiNs7IuefB6Cv2
X-Received: by 2002:a05:6000:4b11:b0:476:7036:f854 with SMTP id
ffacd0b85a97d-47f622f83ccmr11899817f8f.21.1784475102735;
Sun, 19 Jul 2026 08:31:42 -0700 (PDT)
Received: from localhost.localdomain
([2a0d:3344:2841:7708:a101:2b8a:f76:a00f])
by smtp.gmail.com with ESMTPSA id
ffacd0b85a97d-47f63edd7d3sm20420729f8f.25.2026.07.19.08.31.40
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Sun, 19 Jul 2026 08:31:42 -0700 (PDT)
From: Aureal <juanmanuellopezcarrillo@gmail.com>
To: Michael Turquette <mturquette@baylibre.com>,
Stephen Boyd <sboyd@kernel.org>,
Chen-Yu Tsai <wens@kernel.org>,
Jernej Skrabec <jernej.skrabec@gmail.com>,
Samuel Holland <samuel@sholland.org>
Cc: Brian Masney <bmasney@redhat.com>, linux-clk@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev,
linux-kernel@vger.kernel.org,
=?utf-8?q?Juan_Manuel_L=C3=B3pez_Carrillo?= <juanmanuellopezcarrillo@gmail.com>
Subject: [PATCH] clk: sunxi-ng: div: implement set_rate_and_parent
Date: Sun, 19 Jul 2026 17:31:22 +0200
Message-ID: <20260719153122.892013-1-juanmanuellopezcarrillo@gmail.com>
X-Mailer: git-send-email 2.47.3
Precedence: bulk
X-Mailing-List: linux-sunxi@lists.linux.dev
List-Id: <linux-sunxi.lists.linux.dev>
List-Subscribe: <mailto:linux-sunxi+subscribe@lists.linux.dev>
List-Unsubscribe: <mailto:linux-sunxi+unsubscribe@lists.linux.dev>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
X-Rspamd-Server: rspamd-worker-8404
X-Spamd-Result: default: False [-0.16 / 15.00];
BAYES_HAM(-5.50)[100.00%];
RBL_SENDERSCORE(2.00)[172.234.253.10:from];
SUSPICIOUS_RECIPS(1.50)[];
MID_CONTAINS_FROM(1.00)[];
DMARC_POLICY_SOFTFAIL(1.00)[gmail.com : SPF not aligned (relaxed),
No valid DKIM,none];
MAILLIST(-0.15)[generic];
MIME_GOOD(-0.10)[text/plain];
BAD_REP_POLICIES(0.10)[];
HAS_LIST_UNSUB(-0.01)[];
FREEMAIL_CC(0.00)[redhat.com,vger.kernel.org,lists.infradead.org,lists.linux.dev,gmail.com];
FROM_HAS_DN(0.00)[];
FORGED_SENDER_MAILLIST(0.00)[];
PRECEDENCE_BULK(0.00)[];
DBL_BLOCKED_OPENRESOLVER(0.00)[sea.lore.kernel.org:rdns,sea.lore.kernel.org:helo,baylibre.com:email];
TAGGED_RCPT(0.00)[];
FUZZY_BLOCKED(0.00)[rspamd.com];
RCVD_COUNT_FIVE(0.00)[6];
TAGGED_FROM(0.00)[bounces-24528-noreply=patchwork.local];
R_SPF_ALLOW(0.00)[+ip4:172.234.253.10];
RCPT_COUNT_SEVEN(0.00)[11];
FREEMAIL_FROM(0.00)[gmail.com];
TO_DN_SOME(0.00)[];
FROM_NEQ_ENVFROM(0.00)[juanmanuellopezcarrillo@gmail.com,linux-sunxi@lists.linux.dev];
FREEMAIL_TO(0.00)[baylibre.com,kernel.org,gmail.com,sholland.org];
MIME_TRACE(0.00)[0:+];
ASN(0.00)[asn:63949, ipnet:172.234.224.0/19, country:SG];
FORGED_RECIPIENTS_MAILLIST(0.00)[];
ARC_ALLOW(0.00)[subspace.kernel.org:s=arc-20240116:i=1];
RCVD_TLS_LAST(0.00)[];
RCVD_VIA_SMTP_AUTH(0.00)[]
X-Rspamd-Queue-Id: C0AD11C2C23
X-MORS-Enabled: yes
X-MORS-DOMAIN: patchwork.local
X-MORS-HOSTING: hosting172546
X-MORS-USER: hosting172546
X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?=
|
| Series |
clk: sunxi-ng: div: implement set_rate_and_parent
|
|
Commit Message
Juan Manuel López Carrillo
July 19, 2026, 3:31 p.m. UTC
From: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com> When a rate change on a ccu_div clock also switches its parent, the clk core, in the absence of a .set_rate_and_parent op, programs the parent first and the divider second. If the new parent is faster than the old one, the clock transiently runs at new_parent_rate/old_divider between the two register writes, overshooting both the old and the requested rate and potentially violating the consumer's maximum allowed frequency. This is not theoretical. On the Allwinner A523/T527 the GPU clock is a ccu_div muxing between pll-gpu and the fixed pll-periph0 outputs: going from 600 MHz (pll-periph0-600M, M=1) down to 400 or 200 MHz (both derived from pll-periph0-800M) makes the Mali G57 run at 800 MHz for the window between the two writes, 33% above the vendor's maximum operating point. Observed and validated on an Orange Pi 4A (T527) with a downstream GPU devfreq setup; mainline does not yet describe GPU OPPs for this SoC, but any ccu_div consumer whose set_rate ends up crossing parents is affected. Implement .set_rate_and_parent with the same ordering rule as clk_composite_set_rate_and_parent(): if keeping the current divider while switching the mux would overshoot the requested rate, program the divider first, otherwise switch the mux first. The intermediate rate then never exceeds both the old and the new rate. Clocks using a prediv feature keep the historical mux-then-divider order: the prediv helpers look the prediv up by the current parent, which is ambiguous while both are changing. Fixes: e9b93213103f ("clk: sunxi-ng: Add divider") Signed-off-by: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com> --- Note: this touches the same area of ccu_div.c as patch 2/4 of the pending series "clk: sun6i-rtc: Add support for Allwinner A733 SoC" v5 (<20260717-a733-rtc-v5-2-3874cc26abf7@baylibre.com>), which adds ccu_rodiv_ops right after ccu_div_ops. The conflict is trivial (context only); happy to rebase on top of it if it lands first. drivers/clk/sunxi-ng/ccu_div.c | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
Comments
On Sun, Jul 19, 2026 at 11:31 PM Aureal <juanmanuellopezcarrillo@gmail.com> wrote: > > From: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com> > > When a rate change on a ccu_div clock also switches its parent, the > clk core, in the absence of a .set_rate_and_parent op, programs the > parent first and the divider second. If the new parent is faster than > the old one, the clock transiently runs at new_parent_rate/old_divider > between the two register writes, overshooting both the old and the > requested rate and potentially violating the consumer's maximum > allowed frequency. > > This is not theoretical. On the Allwinner A523/T527 the GPU clock is > a ccu_div muxing between pll-gpu and the fixed pll-periph0 outputs: > going from 600 MHz (pll-periph0-600M, M=1) down to 400 or 200 MHz > (both derived from pll-periph0-800M) makes the Mali G57 run at 800 MHz > for the window between the two writes, 33% above the vendor's maximum > operating point. Observed and validated on an Orange Pi 4A (T527) > with a downstream GPU devfreq setup; mainline does not yet describe > GPU OPPs for this SoC, but any ccu_div consumer whose set_rate ends up > crossing parents is affected. > > Implement .set_rate_and_parent with the same ordering rule as > clk_composite_set_rate_and_parent(): if keeping the current divider > while switching the mux would overshoot the requested rate, program > the divider first, otherwise switch the mux first. The intermediate > rate then never exceeds both the old and the new rate. > > Clocks using a prediv feature keep the historical mux-then-divider > order: the prediv helpers look the prediv up by the current parent, > which is ambiguous while both are changing. > > Fixes: e9b93213103f ("clk: sunxi-ng: Add divider") > Signed-off-by: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com> Reviewed-by: Chen-Yu Tsai <wens@kernel.org> So the patch itself is OK, but I think there is also something wrong with the GPU mod clock. The GPU clock is not a standard divider, but actually a fractional one. The formula for the output is Clock Source * ((16-M)/16) with M being 0~15. And we're also missing a notifier to switch the GPU clock away from the PLL while the PLL is being changed. Do you plan on implementing GPU DVFS on mainline? > --- > Note: this touches the same area of ccu_div.c as patch 2/4 of the > pending series "clk: sun6i-rtc: Add support for Allwinner A733 SoC" v5 > (<20260717-a733-rtc-v5-2-3874cc26abf7@baylibre.com>), which adds > ccu_rodiv_ops right after ccu_div_ops. The conflict is trivial > (context only); happy to rebase on top of it if it lands first. That is manageable. Thanks for the heads up. ChenYu > > drivers/clk/sunxi-ng/ccu_div.c | 36 ++++++++++++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > > diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c > index 62d680ccb..9024bcd8c 100644 > --- a/drivers/clk/sunxi-ng/ccu_div.c > +++ b/drivers/clk/sunxi-ng/ccu_div.c > @@ -130,6 +130,41 @@ static int ccu_div_set_parent(struct clk_hw *hw, u8 index) > return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index); > } > > +static int ccu_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate, u8 index) > +{ > + struct ccu_div *cd = hw_to_ccu_div(hw); > + > + /* > + * The predivider helpers look it up through the current parent, > + * which is ambiguous while both the parent and the divider are > + * changing, so keep the mux-then-divider order the core would > + * have used for those clocks. > + */ > + if (cd->common.features & (CCU_FEATURE_VARIABLE_PREDIV | > + CCU_FEATURE_FIXED_PREDIV | > + CCU_FEATURE_ALL_PREDIV)) { > + ccu_div_set_parent(hw, index); > + return ccu_div_set_rate(hw, rate, parent_rate); > + } > + > + /* > + * Same ordering rule as clk_composite_set_rate_and_parent(): if > + * switching the mux with the current divider would overshoot the > + * requested rate, program the divider first, so the intermediate > + * rate never exceeds both the old and the new rate. > + */ > + if (ccu_div_recalc_rate(hw, parent_rate) > rate) { > + ccu_div_set_rate(hw, rate, parent_rate); > + ccu_div_set_parent(hw, index); > + } else { > + ccu_div_set_parent(hw, index); > + ccu_div_set_rate(hw, rate, parent_rate); > + } > + > + return 0; > +} > + > const struct clk_ops ccu_div_ops = { > .disable = ccu_div_disable, > .enable = ccu_div_enable, > @@ -141,5 +176,6 @@ const struct clk_ops ccu_div_ops = { > .determine_rate = ccu_div_determine_rate, > .recalc_rate = ccu_div_recalc_rate, > .set_rate = ccu_div_set_rate, > + .set_rate_and_parent = ccu_div_set_rate_and_parent, > }; > EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU"); > > base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda > -- > 2.47.3 >
> Reviewed-by: Chen-Yu Tsai <wens@kernel.org> Thanks a lot for the quick review! > So the patch itself is OK, but I think there is also something wrong > with the GPU mod clock. The GPU clock is not a standard divider, but > actually a fractional one. The formula for the output is > > Clock Source * ((16-M)/16) > > with M being 0~15. You were right, and it was worse than I expected. I checked the T527 user manual (v0.92, section 2.7.6.58: "FACTOR_M: mask M cycles at 16 cycles") and then measured it on the Orange Pi 4A, forcing each OPP and reading the real GPU frequency with the Mali cycle counter. With the current linear model: OPP request programmed measured 150 MHz 600M, M=3 ~487 MHz 200 MHz 800M, M=3 648 MHz 300 MHz 600M, M=1 560 MHz 400 MHz 800M, M=1 749 MHz 600 MHz 600M, M=0 599 MHz so every OPP below 600 MHz silently overclocks (thermal throttling to "400 MHz" actually raises the clock to 750 MHz). Interestingly the vendor BSP models this register as a linear divider too, so the vendor kernel has the same mislabelling; it also removed the 800M parent from its parent list citing GPU job faults. I have a fix working: a small ccu type implementing the cycle-masking semantics, with the A523 GPU clock switched over to it, the 800M parent dropped from the selectable parents, and the OPP table for the Orange Pi 4A. Re-measured with the same cycle-counter method the five OPPs now come out at 149/199/300/399/597 MHz from the intended parents. I'll send it as a follow-up series referencing this thread. > And we're also missing a notifier to switch the GPU clock away from > the PLL while the PLL is being changed. Agreed — the series also registers the existing sunxi-ng mux notifier on pll-gpu (cpux precedent), parking the GPU on pll-periph0-600M during PLL rate changes. The manual states the mux switch is glitch-free. Nothing retunes pll-gpu at runtime yet with the standard OPPs, but the higher speed-bin operating points (648-792 MHz) will need it as a live parent. > Do you plan on implementing GPU DVFS on mainline? Yes — see above; the series is on its way. The speed-bin OPPs (SID efuse gated) are left for a follow-up. Happy to test any related series on this board in the meantime. Juan Manuel
diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c index 62d680ccb..9024bcd8c 100644 --- a/drivers/clk/sunxi-ng/ccu_div.c +++ b/drivers/clk/sunxi-ng/ccu_div.c @@ -130,6 +130,41 @@ static int ccu_div_set_parent(struct clk_hw *hw, u8 index) return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index); } +static int ccu_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index) +{ + struct ccu_div *cd = hw_to_ccu_div(hw); + + /* + * The predivider helpers look it up through the current parent, + * which is ambiguous while both the parent and the divider are + * changing, so keep the mux-then-divider order the core would + * have used for those clocks. + */ + if (cd->common.features & (CCU_FEATURE_VARIABLE_PREDIV | + CCU_FEATURE_FIXED_PREDIV | + CCU_FEATURE_ALL_PREDIV)) { + ccu_div_set_parent(hw, index); + return ccu_div_set_rate(hw, rate, parent_rate); + } + + /* + * Same ordering rule as clk_composite_set_rate_and_parent(): if + * switching the mux with the current divider would overshoot the + * requested rate, program the divider first, so the intermediate + * rate never exceeds both the old and the new rate. + */ + if (ccu_div_recalc_rate(hw, parent_rate) > rate) { + ccu_div_set_rate(hw, rate, parent_rate); + ccu_div_set_parent(hw, index); + } else { + ccu_div_set_parent(hw, index); + ccu_div_set_rate(hw, rate, parent_rate); + } + + return 0; +} + const struct clk_ops ccu_div_ops = { .disable = ccu_div_disable, .enable = ccu_div_enable, @@ -141,5 +176,6 @@ const struct clk_ops ccu_div_ops = { .determine_rate = ccu_div_determine_rate, .recalc_rate = ccu_div_recalc_rate, .set_rate = ccu_div_set_rate, + .set_rate_and_parent = ccu_div_set_rate_and_parent, }; EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU");