From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peng Fan Date: Fri, 16 Aug 2019 09:55:05 +0000 Subject: [U-Boot] [PATCH V2 2/4] clk: prograte clk enable/disable to parent In-Reply-To: <20190816100740.22725-1-peng.fan@nxp.com> References: <20190816100740.22725-1-peng.fan@nxp.com> Message-ID: <20190816100740.22725-2-peng.fan@nxp.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On i.MX8MM, thinking such as clk path OSC->PLL->PLL GATE->CCM ROOT->CCGR GATE->Device Only enabling CCGR GATE is not enough, we also need to enable PLL GATE to make sure the clk path work. So when enabling CCGR GATE, we could prograte to enabling PLL GATE to make life easier. Signed-off-by: Peng Fan --- V2: Improve commit log Check enable_count when enable/disable to avoid touch hardware following Linux drivers/clk/clk-uclass.c | 77 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index cee4d912b0..d083d43727 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -449,13 +449,45 @@ int clk_set_parent(struct clk *clk, struct clk *parent) int clk_enable(struct clk *clk) { const struct clk_ops *ops = clk_dev_ops(clk->dev); + struct clk *clkp = NULL; + int ret; debug("%s(clk=%p)\n", __func__, clk); - if (!ops->enable) - return -ENOSYS; + if (CONFIG_IS_ENABLED(CLK_CCF)) { + /* Take id 0 as a non-valid clk, such as dummy */ + if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + if (clkp->enable_count) { + clkp->enable_count++; + return 0; + } + if (clkp->dev->parent && + device_get_uclass_id(clkp->dev) == UCLASS_CLK) { + ret = clk_enable(dev_get_clk_ptr(clkp->dev->parent)); + if (ret) { + printf("Enable %s failed\n", + clkp->dev->parent->name); + return ret; + } + } + } - return ops->enable(clk); + if (ops->enable) { + ret = ops->enable(clk); + if (ret) { + printf("Enable %s failed\n", clk->dev->name); + return ret; + } + } + if (clkp) + clkp->enable_count++; + } else { + if (!ops->enable) + return -ENOSYS; + return ops->enable(clk); + } + + return 0; } int clk_enable_bulk(struct clk_bulk *bulk) @@ -474,13 +506,46 @@ int clk_enable_bulk(struct clk_bulk *bulk) int clk_disable(struct clk *clk) { const struct clk_ops *ops = clk_dev_ops(clk->dev); + struct clk *clkp = NULL; + int ret; debug("%s(clk=%p)\n", __func__, clk); - if (!ops->disable) - return -ENOSYS; + if (CONFIG_IS_ENABLED(CLK_CCF)) { + if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + if (clkp->enable_count == 0) { + printf("clk %s already disabled\n", + clkp->dev->name); + return 0; + } - return ops->disable(clk); + if (--clkp->enable_count > 0) + return 0; + } + + if (ops->disable) { + ret = ops->disable(clk); + if (ret) + return ret; + } + + if (clkp && clkp->dev->parent && + device_get_uclass_id(clkp->dev) == UCLASS_CLK) { + ret = clk_disable(dev_get_clk_ptr(clkp->dev->parent)); + if (ret) { + printf("Disable %s failed\n", + clkp->dev->parent->name); + return ret; + } + } + } else { + if (!ops->disable) + return -ENOSYS; + + return ops->disable(clk); + } + + return 0; } int clk_disable_bulk(struct clk_bulk *bulk) -- 2.16.4